KNN算法
# 模型参数与超参数 # 模型参数是模型内部的配置变量,可以用数据估计模型参数的值;模型超参数是模型外部的配置,必须手动设置参数的值。 # 交叉验证 # 我们解决机器学习问题的一般步骤: # 数据预处理:重复缺失异常值处理,特征选择,特征变换,特征降维 # 数据建模:机器学习的问题分为两类:分类和回归,我们根据问题选择合适的模型 # 模型评估:对模型的预测结果做一个评估,常用指标accuracy,recall,F1,PRC,ROC_AUC,IOU等等。 #交叉验证就是我们模型评估的一个有效的手段。 # 如果我们把用于训练的数据集去验证模型,那么就很容易出现过拟合。所以一般我们把数据集分为训练集和测试集,但是这样也会出现很多的问题。 # 举个栗子,我们平时做的模拟题就是训练集,考试试卷就是测试集,如果考试的时候全是平时做过的模拟原题,那还有什么意义呢,全都是满分, # 实际上真的有满分的水平嘛,再出一道没做过的题目还是不会,这个情况就是过拟合。但是模拟题过简单,考试题过难,这样结果也不理想。 # 为了让我们的模型充分 反应真实效果,我们引入了交叉验证。 # 交叉验证的基本思想是把在某种意义下将原始数据进行分组,一部分做为训练集,另一部分做为验证集,首先用训练集对分类器进行训练,再利用验证集来测试训练得到的模型, # 以此来做为评价分类器的性能指标。如上图所示,我们将训练集平均分成十份,每次将序号递增的一份拿出来当作测试集,其余九份作为训练集,然后迭代十次, # 将10次的结果进行平均,以此作为模型的指标。 # 线性回归和KNN的区别 # 1)KNN既可以做回归,也可以做分类。那么如果要做回归的话,什么时候用线性回归什么时候用KNN呢?事实证明,如果数据之间线性关系比较明显的话, # 线性回归会优于KNN,如果数据之间线性关系不明显的话,KNN会比较好一些。但总得来说,这两个都是机器学习中最简单,最基础的模型。 # 随着维度的上升,这两个模型,尤其是KNN会面临失效的问题,这就是所谓的维度灾难 # 2)线性回归不受纲量的影响,KNN受纲量的影响,所以KNN最好需要先进行标准化处理。 # KNN算法 # KNN(K-Nearest Neighbor)是最简单的机器学习算法之一,可以用于分类和回归,是一种监督学习算法。 # 它的思路是这样,如果一个样本在特征空间中的K个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别。 # 也就是说,该方法在定类决策上只依据最邻近的一个或者几个样本的类别来决定待分样本所属的类别 # 超参数 # n_neighbors # weights uniform,distance # 建模 # from sklearn.neighbors import KNeighborsRegressor,KNeighborsClassifier # x_train,x_test,y_train,y_test = train_test_split(X,y,test_size=0.25,random_state=3) # knn = KNeighborsRegressor() # knn.fit(x_train,y_train) # 超参数调整 # 借助 GridSearchCV 网格搜索 # 应用场景: 选择合适的超参数 # 这是一种机器学习模型通常都会用到的模型调参方法,它能够返回最好的模型参数组合,采用这些参数建模便能得到最好的模型 # from sklearn.model_selection import GridSearchCV # parameters = {'n_neighbors':range(1,10),'weights':['uniform','distance']} # 定义需要尝试的超参数组合 # clf = GridSearchCV(estimator=knn,param_grid=parameters,n_jobs=-1,scoring='r2',cv=5,verbose=10) # scoring 根据线性回归还是逻辑回归,选择不同的模型评估标准。线性-->R2,MSE 逻辑--> f1,recall,accuracy # estimator 评估器,即对哪个模型调整超参数 # cv 交叉验证折数 # clf.fit(x_train,y_train) # clf.best_score_ # clf.best_estimator_ # 最好的超参数训练好的模型。已经训练好了,直接拿来用,不用再fit了!!! # clf.best_estimator_.predict(x_test) # print(clf.best_estimator_.score(x_train,y_train)) # print(clf.best_estimator_.score(x_test,y_test)) # 数据标准化 # 实际也是属于预处理的一种 # from sklearn.preprocessing import StandardScaler,MinMaxScaler # scaler = MinMaxScaler() # x_train_sca = scaler.fit_transform(x_train) 对测试集和训练集使用的方法不同。 # x_test_sca = scaler.transform(x_test) # knn.fit(x_train_sca,y_train) # print(knn.score(x_train_sca,y_train)) # print(knn.score(x_test_sca,y_test)) # 流水线 # Pipeline可以将许多算法模型串联起来,比如将特征提取、归一化、分类组织在一起形成一个典型的机器学习问题工作流。主要带来两点好处: # 1、直接调用fit和predict方法来对pipeline中的所有算法模型进行训练和预测。 # 2、可以结合grid search对参数进行选择。 # 注意: # 除了最后一个tansform,其余的transform必须实现fit_transform函数 # 在自定义transform类时,必须要实现fit_transform函数,因为fit_transform是下一个transform的参数 # 每一步transform返回的值是numpy的array形式数据 # 流水线可以将每个评估器视为一个步骤,然后将多个步骤作为一个整体而依次执行。 # 流水线具有最后一个评估器的所有方法,当通过流水线对象调用方法时,会执行这样的过程: # 如果是fit方法,则会对前n-1个评估器依次调用fit_transform方法,然后在最后一个评估器上调用fit方法 # 如果是其它(eg:predict)方法,则会对前n-1个评估器依次调用transform方法,然后在最后一个评估器上调用该方法(predict)。 # from sklearn.pipeline import Pipeline # steps = [('scaler',MinMaxScaler()),('knn',KNeighborsRegressor())] # p = Pipeline(steps=steps) # p.set_params(knn__n_neighbors=5,knn__weights='distance') # p.fit(x_train,y_train) # print(p.score(x_train,y_train)) # print(p.score(x_test,y_test))
朴素贝叶斯
# 先验概率和后验概率 # 先验概率(prior probability) # 是指根据以往经验和分析得到的概率,如全概率公式,它往往作为"由因求果"问题中的"因"出现的概率。 # 是我们人在未知条件下对事件发生可能性猜测的数学表示 # 后验概率 # 事情已经发生,要求这件事情发生的原因是由某个因素引起的可能性的大小 # 所谓的后验概率,是一种果因概率,即在一个结果已经发生的条件下,可能是其中某一个原因造成的概率有多大。 # 举个例子,桌子上如果有一块肉喝一瓶醋,如果吃了一块肉,然后觉得是酸的,那认为肉里加了醋的概率有多大? # 回答:80%可能性加了醋。OK,你已经进行了一次后验概率的猜测 # 贝叶斯公式 # 之所以贝叶斯方法在机器学习中如此重要,可能就是因为人们希望机器人能像人那样思考,而很多问题是需要计算机在已知条件下做出最佳决策的决策, # 而贝叶斯公式就是对人脑在已知条件下做出直觉判断的一种数学表示。 # 这里引用一段"概率论与数理统计"中关于贝叶斯公式的解释: # 如果我们把事件A看做‘结果’,把诸事件B1、B2…看做导致这个结果的‘原因’,则可以形象地把全概率公式看做成为‘由原因推结果’; # 而贝叶斯公式则恰好相反,其作用于‘由结果推原因’;现在有一个‘结果A’已发生,在众多可能的‘原因’中,到底是哪一个导致了这结果。 # 18世纪英国业余数学家托马斯·贝叶斯(Thomas Bayes,1702~1761)提出过一种看上去似乎显而易见的观点:“用客观的新信息更新我们最初关于某 # 个事物的信念后,我们就会得到一个新的、改进了的信念。” 这个研究成果,因为简单而显得平淡无奇,直到他死后的两年才于1763年由他的朋友 # 理查德·普莱斯帮助发表。它的数学原理很容易理解,简单说就是,如果你看到一个人总是做一些好事,则会推断那个人多半会是一个好人。 这就是说, # 当你不能准确知悉一个事物的本质时,你可以依靠与事物特定本质相关的事件出现的多少去判断其本质属性的概率。用数学语言表达就是:支持某项属性 # 的事件发生得愈多,则该属性成立的可能性就愈大。与其他统计学方法不同,贝叶斯方法建立在主观判断的基础上,你可以先估计一个值,然后根据客观 # 事实不断修正。 # 贝叶斯公式现在已经非常流行,甚至在热门美剧《生活大爆炸》中谢耳朵也秀了一下。但它真正得到重视和广泛应用却是最近二三十年的事,其间被埋没了 # 200多年。这是为什么呢?原因在于我们有另外一种数学工具——经典统计学,或者叫频率主义统计学(我们在学校学的主要是这种统计学),它在200多年 # 的时间里一直表现不错。从理论上讲,它可以揭示一切现象产生的原因,既不需要构建模型,也不需要默认条件,只要进行足够多次的测量,隐藏在数据 # 背后的原因就会自动揭开面纱。 # 在经典统计学看来,科学是关于客观事实的研究,我们只要反复观察一个可重复的现象,直到积累了足够多的数据,就能从中推断出有意义的规律。而 # 贝叶斯方法却要求科学家像算命先生一样,从主观猜测出发,这显然不符合科学精神。就连拉普拉斯后来也放弃了贝叶斯方法这一思路,转向经典统计学。 # 因为他发现,如果数据量足够大,人们完全可以通过直接研究这些样本来推断总体的规律。 # 长期以来,贝叶斯方法虽然没有得到主流学界的认可,但其实我们经常会不自觉地应用它来进行决策,而且还非常有效。比如在一个陌生的地方找餐馆吃饭, # 因为之前不了解哪家餐馆好,似乎只能随机选择,但实际上并非如此,我们会根据贝叶斯方法,利用以往积累的经验来提供判断的线索。经验告诉我们, # 通常那些坐满了客人的餐馆的食物要更美味些,而那些客人寥寥的餐馆,食物可能不怎么样而且可能会被宰。这样,我们就往往通过观察餐厅的上座率来 # 选择餐馆就餐。这就是我们根据先验知识进行的主观判断。在吃过以后我们对这个餐馆有了更多实际的了解,以后再选择时就更加容易了。所以说, # 在我们认识事物不全面的情况下,贝叶斯方法是一种很好的利用经验帮助作出更合理判断的方法。 # 总的说来,贝叶斯公式是求一个条件概率,也就是计算简单条件下发生的复杂事件的概率。 # 简单的总结一下,我们可以把贝叶斯理解成条件概率的一种变形,这样你会在理解了条件概率之后更容易明白贝叶斯公式的意义。但是如何想用好它必须要 # 理解贝叶斯公式的背后意义,它描述了一种用证据不断去修改事实的一种方式。这种思考方式更加贴近现实中我们去思考问题的方式。 # 比如我们在验证一封邮件到底是否是一封垃圾邮件呢?首先预设某封邮件是垃圾邮件的概率为50%,然后根据以往的邮件进行统计,发现出现“广告”字样 # 是垃圾邮件的概率为90%,而不是垃圾邮件的概率为1%。那我们就可以用贝叶斯法则来判断一封带有”广告“字样的邮件是否是垃圾邮件了。 # 贝叶斯的核心还是p(x|y) 在y发生的情况下 x的概率,在某种场景下,垃圾邮件的概率很高。 # 朴素贝叶斯 # 朴素贝叶斯算法是建立在每一个特征值之间时独立的基础上的监督学习分类算法,而这也是称他为 “朴素”贝叶斯的缘由,在现实环境中, # 很难达到两个特征值之间绝对的相互独立。 # 朴素贝叶斯分类 # 高斯朴素贝叶斯 # 假设特征的似然为高斯分布 eg:iris数据,人的身高 # 先验为高斯分布的朴素贝叶斯 # 伯努利朴素贝叶斯 # 先验为伯努利分布的朴素贝叶斯,适用于样本很稀松的二元离散值或很稀松的多元离散值情况 # eg:文本分类,特征是单词,值是 单词出现的次数 # 多项式朴素贝叶斯 # 先验为多项式的分布的朴素贝叶斯 # 朴素贝叶斯与逻辑回归的区别 # 逻辑回归 vs 高斯朴素贝叶斯,这其实代表这两类模型的 PK。逻辑回归是判别模型(discriminative model)的代表,而朴素贝叶斯是 # 生成模型(generative model)的代表。 # 从评价一个分类器在样本外准确性的 generalization error 来说,判别模型和生成模型各有千秋。虽然学术界和业界普遍认为判别模型的精度更高,但
# Ng and Jordan # (2002) 通过理论和实证表明,在训练集样本数量很少的情况下,生成模型的效果往往优于判别模型。 # 1. 两种模型的收敛速度不同:逻辑回归的收敛速度是 O(n);而朴素贝叶斯的收敛速度是 O(logn)。 # 2. 在极限情况下(即当二者都收敛后),逻辑回归的误差小于朴素贝叶斯的误差。 # 拉普拉斯平滑 # from sklearn.naive_bayes import GaussianNB,BernoulliNB,MultinomialNB # X,y = datasets.load_iris(return_X_y=True) # clf = GaussianNB() # clf.fit(x_train,y_train) # clf.class_count_ # 每个类别的样本数量 # clf.feature_count_ # 每个特征在每个类别下发生(出现)的次数 # np.exp(clf.feature_log_prob_) # 取对数,查看原有概率 # 每个类别下,每个特征所占的比例(概率)即 p(x|y) # np.exp(clf.class_log_prior_) # 每个类别所占样本比重。即p(y),查看原有概率,需指数还原。 # pd.get_dummies(data) !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! # Convert categorical variable into dummy/indicator variables. # 没想到在 多项式贝叶斯 用到了one-hat。从另一个角度想,也是理所当然的。 # 这个方法学习到了,可以将dataframe便捷迅速的转为one-hot样式。
决策树
# 信息熵 # 计算公式:H(x) = E[I(xi)] = E[ log(2,1/p(xi)) ] = -∑p(xi)log(2,p(xi)) (i=1,2,..n) # 其中,x表示随机变量,与之相对应的是所有可能输出的集合,定义为符号集,随机变量的输出用x表示。 # P(x)表示输出概率函数。变量的不确定性越大,熵也就越大,把它搞清楚所需要的信息量也就越大. # https://wiki.mbalib.com/wiki/%E4%BF%A1%E6%81%AF%E7%86%B5 # 基尼不纯度 # 是用于决策树编程中的一个专业术语。 # 基尼不纯度,是指将来自集合中的某种结果随机应用在集合中,某一数据项的预期误差率。 # 基尼不纯度越小,纯度越高,集合的有序程度越高,分类的效果越好 # 信息增益 # 指用某个特征划分数据集前后的信息熵的差值,准确的说是信息熵减少的数值 # 使用某个特征对数据进行划分后,数据子集的纯度增加,不确定性减少,信息熵降低, # 表明该特征具有一定程度的信息量,带来了正向收益,称之为“信息增益”。 # 决策树 # https://blog.csdn.net/yoggieCDA/article/details/101464287 # 决策树算法在机器学习中算是很经典的一个算法系列了。它既可以作为分类算法,也可以作为回归算法,同时也特别适合集成学习比如随机森林。 # 作为分类算法,使用基尼不纯度,信息熵作为评估标准;作为回归算法,使用MSE/MAE作为评估标准。 # 机器学习算法其实很古老,作为一个码农经常会不停的敲if, else if, else,其实就已经在用到决策树的思想了。只是你有没有想过,有这么多条件, # 用哪个条件特征先做if,哪个条件特征后做if比较优呢?怎么准确的定量选择这个标准就是决策树机器学习算法的关键了。1970年代,一个叫昆兰的大牛 # 找到了用信息论中的熵来度量决策树的决策选择过程,方法一出,它的简洁和高效就引起了轰动,昆兰把这个算法叫做ID3 # 决策树(Decision Tree)是在已知各种情况发生概率的基础上,通过构成决策树来求取净现值的期望值大于等于零的概率,评价项目风险,判断其可行性 # 的决策分析方法,是直观运用概率分析的一种图解法。由于这种决策分支画成图形很像一棵树的枝干,故称决策树。在机器学习中,决策树是一个预测模型, # 他代表的是对象属性与对象值之间的一种映射关系。Entropy = 系统的凌乱程度,使用算法ID3,C4.5和C5.0生成树算法使用熵。这一度量是基于信息学理论 # 中熵的概念。 # 决策树是一种树形结构,其中每个内部节点表示一个属性上的测试,每个分支代表一个测试输出,每个叶节点代表一种类别。 # 分类树(决策树)是一种十分常用的分类方法。他是一种监管学习,所谓监管学习就是给定一堆样本,每个样本都有一组属性和一个类别,这些类别是事先 # 确定的,那么通过学习得到一个分类器,这个分类器能够对新出现的对象给出正确的分类。这样的机器学习就被称之为监督学习。 # 分类 # ID3算法 # C4.5算法 # CART算法 # 首先我们看看决策树算法的优点: # 1)简单直观,生成的决策树很直观。 # 2)基本不需要预处理,不需要提前归一化,处理缺失值。 # 3)使用决策树预测的代价是O(log2m)。 m为样本数。 # 4)既可以处理离散值也可以处理连续值。很多算法只是专注于离散值或者连续值。 # 5)可以处理多维度输出的分类问题。 # 6)相比于神经网络之类的黑盒分类模型,决策树在逻辑上可以得到很好的解释 # 7)可以交叉验证的剪枝来选择模型,从而提高泛化能力。 # 8) 对于异常点的容错能力好,健壮性高。 # 我们再看看决策树算法的缺点: # 1)决策树算法非常容易过拟合,导致泛化能力不强。可以通过设置节点最少样本数量和限制决策树深度来改进。 # 2)决策树会因为样本发生一点点的改动,就会导致树结构的剧烈改变。这个可以通过集成学习之类的方法解决。 # 3)寻找最优的决策树是一个NP难的问题,我们一般是通过启发式方法,容易陷入局部最优。可以通过集成学习之类的方法来改善。 # 4)有些比较复杂的关系,决策树很难学习,比如异或。这个就没有办法了,一般这种关系可以换神经网络分类方法来解决。 # 5)如果某些特征的样本比例过大,生成决策树容易偏向于这些特征。这个可以通过调节样本权重来改善。 # from sklearn.tree import DecisionTreeClassifier # from sklearn.tree import DecisionTreeRegressor # from sklearn import datasets # X,y = datasets.load_iris(return_X_y=True) # clf = DecisionTreeClassifier(criterion='entropy',min_samples_leaf=5,random_state=0) # x_train,x_test,y_train,y_test = train_test_split(X,y,test_size=0.25,random_state=0) # clf.fit(x_train,y_train) # print(clf.score(x_train,y_train)) # print(clf.score(x_test,y_test))
K-means
# 聚类是非监督学习的一种 # K-means # K-means算法是硬聚类算法,是典型的基于原型的目标函数聚类方法的代表,它是数据点到原型的某种距离作为优化的目标函数,利用函数求极值的方法 # 得到迭代运算的调整规则。K-means算法以欧式距离作为相似度测度,它是求对应某一初始聚类中心向量V最优分类,使得评价指标J最小。算法采用误差平方和 # 准则函数作为聚类准则函数。 # k-means与kNN虽然都是以k打头,但却是两类算法——kNN为监督学习中的分类算法,而k-means则是非监督学习中的聚类算法;二者相同之处: # 均利用近邻信息来标注类别。 # 聚类是数据挖掘中一种非常重要的学习流派,指将未标注的样本数据中相似的分为同一类,正所谓“物以类聚,人以群分”嘛。k-means是聚类算法中最为简单、 # 高效的,核心思想:由用户指定k个初始质心(initial centroids),以作为聚类的类别(cluster),重复迭代直至算法收敛。 # 评估标准 # inertia_ 实际上就是SSE # 优化 # K-means++ # MinBatchKmeans # Mini Batch K-Means算法是K-Means算法的变种,采用小批量的数据子集减小计算时间,同时仍试图优化目标函数, # 这里所谓的小批量是指每次训练算法时所随机抽取的数据子集,采用这些随机产生的子集进行训练算法,大大减小了计算时间,与其他算法相比, # 减少了k-均值的收敛时间,小批量k-均值产生的结果,一般只略差于标准算法。 # k-means是最简单的非监督分类算法,knn是最简单的监督分类算法,初学者学完监督学习章节再去学非监督章节会感觉似曾相识, # 原因可能都是用距离作为评价样本间的相似度。下面列举几个区别的地方: # 1)knn是监督学习方法,k-means是非监督学习方法,因此knn需要样本的标记类,k-means不需要; # 肘部法则 # 肘部法则的计算原理是成本函数,成本函数是类别畸变程度之和,每个类的畸变程度等于每个变量点到其类别中心的位置距离平方和,若类内部的成员彼此间 # 越紧凑则类的畸变程度越小,反之,若类内部的成员彼此间越分散则类的畸变程度越大。在选择类别数量上,肘部法则会把不同值的成本函数值画出来。随着值 # 的增大,平均畸变程度会减小;每个类包含的样本数会减少,于是样本离其重心会更近。但是,随着值继续增大,平均畸变程度的改善效果会不断减低。 # 值增大过程中,畸变程度的改善效果下降幅度最大的位置对应的值就是肘部。 from sklearn.model_selection import train_test_split from sklearn.cluster import KMeans,MiniBatchKMeans kmeans = KMeans(n_clusters=3,random_state=0) kmeans.fit(x_train) kmeans.cluster_centers_ # 获取分类后的质心 kmeans.labels_ # 获取每个样本所属的簇。标签的数值对应所属簇的索引 kmeans.score(x_test) kmeans.n_clusters # 获取簇的个数 kmeans.predict(x_test) kmeans.inertia_ # 簇惯性 kmeans.n_iter_ # 获取迭代次数 ---------------------------------------------------------------------------------------------------------- # color = ['r','g','orange'] # c = [color[i] for i in y_train] # plt.scatter(x_train[:,0],x_train[:,1],c=c) # plt.scatter(kmeans.cluster_centers_[:,0],kmeans.cluster_centers_[:,1],marker='x',color=color,s=500) # color = ['r','g','orange'] # color = np.array(color) # !!!!!!! np.ndarray 竟然还有这么一个方法,厉害了!!!!!!!!!!牛逼!!!!!!!!!! # plt.scatter(x_train[:,0],x_train[:,1],c=color[y_train]) # 这两个方法都可以实现,聚类的可视化,但明显下面的方法更高大上。 ndarray 索引接数字,便可将ndarray对应的值取出来,方便极了!!!!