sklearn机器学习
机器学习典型步骤
- 数据采集和标记
- 数据清洗
- 特征选择
- 模型选择和构建
- 模型训练和测试
- 模型性能评估和优化
- 模型保存&使用
过拟合 & 欠拟合
欠拟合(underfitting),也称为高偏差(high bias),因为我们试图用一条直线来拟合样本数据。右边是过拟合(overfitting),也称为高方差(high variance),用了十阶多项式来拟合数据,虽然模型对现有的数据集拟合得很好,但对新数据预测误差却很大。
过拟合:
-
获取更多的训练数据
-
减少输入的特征数量
比如,针对书写识别系统,原来使用200×200的图片,总共40000个特征。优化后,我们可以把图片等比例缩小为10×10的图片,总共100个特征。这样可以大大减少模型的计算量,同时也减少模型的复杂度,改善过拟合问题。
-
正则化
当每个特征xi对预测值y都有少量的贡献时,这样的模型可以良好地工作,这就是正则化的目的,可以用它来解决特征过多时的过拟合问题。
L1范数作为正则项,会让模型参数θ稀疏化,即让模型参数向量里为0的元素尽量多。而L2范数作为正则项,则是让模型参数尽量小,但不会为0,即尽量让每个特征对预测值都有一些小的贡献。
欠拟合:
- 增加有价值的特征
- 增加多项式特征
为什么需要交叉验证数据集?
我们在第1章介绍过的,要把数据集分成训练数据集和测试数据集。一般原则是按照8∶2或7∶3来划分,然后用训练数据集来训练模型,训练出模型参数后再使用测试数据集来测试模型的准确性,根据模型的准确性来评价模型的性能。
另外一个更科学的方法是把数据集分成3份,分别是训练数据集、交叉验证数据集和测试数据集,推荐比例是6∶2∶2。
这个时候我们会用测试数据集算出针对测试数据集的成本Jtest(θ),看哪个模型的测试数据集成本最低,我们就选择这个多项式来拟合数据,但实际上,这是有问题的。测试数据集的最主要功能是测试模型的准确性,需要确保模型“没见过”这些数据。现在我们用测试数据集来选择多项式的阶数d,相当于把测试数据集提前让模型“见过”了。这样选择出来的多项式阶数d本身就是对训练数据集最友好的一个,这样模型的准确性测试就失去了意义。
当然,在实践过程中,很多人直接把数据集分成训练数据集和测试数据集,而没有分出交叉验证数据集。这是因为很多时候并不需要横向去对比不同的模型。在工程上,大多数时候我们最主要的工作不是选择模型,而是获取更多数据、分析数据、挖掘数据。
什么是学习曲线?
为什么需要查准率和召回率来评估模型的好坏?查准率和召回率适合哪些问题领域?
有时候,模型准确性并不能评价一个算法的好坏。比如针对癌症筛查算法,根据统计,普通肿瘤中癌症的概率是0.5%。有个机器学习算法,测试得出的准确率是99.2%,错误率是0.8%。这个算法到底是好还是坏呢?如果努力改进算法,最终得出的准确率是99.5%,错误率是0.5%,模型到底是变好了还是变坏了呢?
坦白讲,如果单纯从模型准确性的指标上很难判断到底是变好了还是变坏了。因为这个事情的先验概率太低了,假如写了一个超级简单的预测函数,总是返回0,即总是认为不会得癌症,那么我们这个超级简单的预测函数的准确率是99.5%,错误率是0.5%。因为总体而言,只有那0.5%真正得癌症的却被我们误判了。
数据预处理 & 特征选择
归一化处理:目的是让算法收敛更快,提升模型拟合过程中的计算效率。进行归一化处理后,当有个新的样本需要计算预测值时,也需要先进行归一化处理,再通过模型来计算预测值,计算出来的预测值要再乘以归一化处理的系数,这样得到的数据才是真实的预测数据。
特征选择:
- 人工选择
- PCA算法
kNN
sklearn.neighbors.KNeighborsClassifier
使用k-近邻算法进行回归拟合
分类问题的预测值是离散的,我们也可以用k-近邻算法在连续区间内对数值进行预测,进行回归拟合。在scikit-learn里,使用k-近邻算法进行回归拟合的算法是sklearn.neighbors.KNeighborsRegressor类。
实例:糖尿病预测
k-近邻算法有哪些变种?
- 普通的k-均值算法
- 带权重的k-均值算法
- 指定半径的k-均值算法: KNeighborsClassifier
线性回归
- 线性回归由类
sklearn.linear_model.LinearRegression
实现 - 多项式由类
sklearn.preprocessing.PolynomialFeatures
实现
那么要怎么添加多项式特征呢?我们需要用一个管道把两个类串起来,即用 sklearn.pipeline.Pipeline
把两个模型串起来。
实例:波士顿房价预测
逻辑回归
逻辑回归算法的名字里虽然带有“回归”二字,但实际上逻辑回归算法是用来解决分类问题的算法。逻辑回归算法的输出是个离散值,这是与线性回归算法的最大区别。
逻辑回归算法为什么要选择Sigmoid函数作为预测函数的模型呢?
严格地讲,不一定非要选择Sigmoid函数作为预测函数。但如果不选择Sigmoid函数,就需要重新选择性质接近的成本函数,这样才能在数学上得到既方便表达、效率又高的成本函数。
乳腺癌检测(数据预处理)
从特征指标里,可以看出,有些指标属于“复合”指标,即由其他的指标经过运算得到的。比如密实度,是由周长和面积计算出来的。不要小看这种运算构建出来的新特征,这是事物内在逻辑关系的体现。
提取特征时,不妨从事物的内在逻辑关系入手,分析已有特征之间的关系,从而构造出新的特征。这一方法在实际工程应用中是常用的特征提取手段。
回到我们讨论的乳腺癌数据集的特征问题中,实际上它只关注10个特征,然后又构造出了每个特征的标准差及最大值,这样每个特征就又衍生出了两个特征,所以总共就有了30个特征。可以通过 cancer.feature_names
变量来查看这些特征的名称。
…
总共114个测试样本,全部预测正确。这里有个疑问,为什么全部都预测正确,而test score却只有0.973684,而不是1呢?答案是,scikit-learn不是使用这个数据来计算分数,因为这个数据不能完全反映误差情况,而是使用预测概率数据来计算模型评分。
朴素贝叶斯算法
在scikit-learn里,朴素贝叶斯算法在sklearn.naive_bayes包里实现,包含了本章介绍的
几种典型的概率分布算法。
GaussianNB
实现了高斯分布的朴素贝叶斯算法MultinomialNB
实现了多项式分布的朴素贝叶斯算法BernoulliNB
实现了伯努利分布的朴素贝叶斯算法
朴素贝叶斯算法在自然语言领域有广泛的应用,本节我们用 MultinomialNB
来实现文档自动分类。
实例:文档自动分类
k-Means均值算法
scikit-learn里的k-均值算法由sklearn.cluster.KMeans类实现。
典型的无监督式学习包括市场细分,即通过分析用户数据,把一个产品的市场进行细分,找出细分人群。另外一个是社交网络分析,分析社交网络中参与人员的不同特点,根据特点区分出不同群体。这些都是无监督式学习里的聚类(Clustering)问题。
k-均值算法算法包含以下两个步骤。
- 给聚类中心分配点。计算所有的训练样例,把每个训练样例分配到距离其最近的聚类中心所在的类别里;
- 移动聚类中心。新的聚类中心移动到这个聚类所有的点的平均值处。
一直重复做上面的动作,直到聚类中心不再移动为止,这时就探索出了数据集的结构了。
KMeans.score()
函数计算k-均值算法拟合后的成本,用负数表示,其绝对值越大,说明成本越高。前面介绍过,k-均值算法成本的物理意义为训练样例到其所属的聚类中心点的距离的平均值,在scikit-learn里,其计算成本的方法略有不同,它是计算训练样例到其所属的聚类中心点的距离的总和。
前面说过,k-均值算法的一个关键参数是k,即聚类个数。从技术角度来讲,k值越大,算法成本越低,这个很容易理解。但从业务角度来看,不是k值越大越好。
实例:文档聚类分析
假设有一个博客平台,用户在平台上发布博客,我们如何对博客进行聚类分析,以方便展示不同类别下的热门文章呢?
决策树
基本概念
什么是信息熵?
我们天天在谈论信息,那么信息要怎么样来量化呢?1948年,香农在他著名的《通信的数学原理》中提出了信息熵(Entropy)的概念,从而解决了信息的量化问题。香农认为,一条信息的信息量和它的不确定性有直接关系。一个问题不确定性越大,要搞清楚这个问题,需要了解的信息就越多,其信息熵就越大。
什么是信息增益?
回到决策树的构建问题上,当我们要构建一个决策树时,应该优先选择哪个特征来划分数据集呢?答案是:遍历所有的特征,分别计算,使用这个特征划分数据集前后信息熵的变化值,然后选择信息熵变化幅度最大的那个特征,来优先作为数据集划分依据。即选择信息增益最大的特征作为分裂节点。
决策树的创建
- 计算数据集划分前的信息熵。
- 遍历所有未作为划分条件的特征,分别计算根据每个特征划分数据集后的信息熵
- 选择信息增益最大的特征,并使用这个特征作为数据划分节点来划分数据
- 递归地处理被划分后的所有子数据集,从未被选择的特征里继续选择最优数据划分特征来划分子数据集。
问题来了,递归过程什么时候结束呢?一般来讲,有两个终止条件,一是所有的特征都用完了,即没有新的特征可以用来进一步划分数据集。二是划分后的信息增益足够小了,这个时候就可以停止递归划分了。针对这个停止条件,需要事先选择信息增益的门限值来作为结束递归的条件。
决策树如何处理连续值的特征?
如果一个特征是连续值怎么办呢?我们以本章开头的图7-1为例,假设我们有个精力测试仪器,测出来的是一个0~100的数字,这是个连续值,这个时候怎么用决策树来建模呢?答案是:离散化。我们需要对数据进行离散化处理。例如,当精力指数小于等于40时标识为低,当大于40且小于等于70时标识为中,当大于70时标识为高。经过离散处理后,就可以用来构建决策树了。要离散化成几个类别,这个往往和具体的业务相关。
正则项处理
最大化信息增益来选择特征,在决策树的构建过程中,容易造成优先选择类别最多的特征来进行分类。举一个极端的例子,我们把某个产品的唯一标识符ID作为特征之一加入到数据集中,那么构建决策树时,就会优先选择产品ID来作为划分特征,因为这样划分出来的数据,每个叶子节点只有一个样本,划分后的子数据集最“纯净”,其信息增益最大。
这不是我们希望看到的结果。解决办法是,计算划分后的子数据集的信息熵时,加上一个与类别个数成正比的正则项,来作为最后的信息熵。这样,当算法选择的某个类别较多的特征,使信息熵较小时,由于受到类别个数的正则项惩罚,导致最终的信息熵也比较大。这样通过合适的参数,可以使算法训练得到某种程度的平衡。
另外一个解决办法是使用信息增益比来作为特征选择的标准。具体可参阅本章的扩展阅读。
算法分类
-
ID3算法
使用信息增益作为特征选择指标的决策树构建算法,称为ID3算法
-
CART算法
使用基尼不纯度来作为特征选择标准
-
C4.5
作为ID3算法的改进
-
C5.0
它运算效率更高,使用内存更小,创建出来的决策树更小,并且准确性更高,适合大数据集的决策树构建。
剪枝算法
使用决策树模型拟合数据时,容易造成过拟合。解决过拟合的方法是对决策树进行剪枝处理。决策树的剪枝有两种思路:前剪枝(Pre-Pruning)和后剪枝(Post-Pruning)。
前剪枝是在构造决策树的同时进行剪枝。在决策树的构建过程中,如果无法进一步降低信息熵的情况下,就会停止创建分支。为了避免过拟合,可以设定一个阈值,信息熵减小的数量小于这个阈值,即使还可以继续降低熵,也停止继续创建分支。这种方法称为前剪枝。还有一些简单的前剪枝方法,如限制叶子节点的样本个数,当样本个数小于一定的阈值时,即不再继续创建分支。
后剪枝是目前较普遍的做法。
后剪枝是指决策树构造完成后进行剪枝。剪枝的过程是对拥有同样父节点的一组节点进行检查,判断如果将其合并,信息熵的增加量是否小于某一阈值。如果小于阈值,则这一组节点可以合并一个节点。后剪枝的过程是删除一些子树,然后用子树的根节点代替,来作为新的叶子节点。这个新叶子节点所标识的类别通过大多数原则来确定,即把这个叶子节点里样本最多的类别,作为这个叶子节点的类别。
实例:预测泰坦尼克号幸存者
从输出数据中可以看出,针对训练样本评分很高,但针对交叉验证数据集评分比较低,两者差距较大。很明显,这是过拟合的特征。解决决策树过拟合的方法是剪枝,包括前剪枝和后剪枝。
不幸的是,scikit-learn不支持后剪枝,但提供一系列的模型参数进行前剪枝。例如,我们通过max_depth参数限定决策树的深度,当决策树达到限定的深度时,就不再进行分裂了。这样就可以在一定程度上避免过拟合。
接下来,就是:优化模型参数。
问题来了,难道我们要手动一个个地去试参数,然后找出最优的参数吗?一个最直观的解决办法是选择一系列参数的值,然后分别计算用指定参数训练出来的模型的评分数据。还可以把两者的关系画出来,直观地看到参数值与模型准确度的关系。
模型参数选择工具包
细心的读者会发现我们介绍的模型参数优化方法有两个问题。其一,数据不稳定。读者朋友们可以试着运行一下示例代码,每次重新把数据集划分成训练数据集和交叉验证数据集后,选择出来的模型参数就不是最优的了。例如,原来选择出来的决策树深度为7是最优的,第二次计算出来的决策树的最优深度可能变成了6。其二,不能一次选择多个参数。例如,我们想要考察max_depth和min_samples_leaf两个结合起来的最优参数就没办法实现。
解决这个问题的方法是多次计算,求平均值。具体来讲,就是针对模型的某个特定参数值,多次划分数据集,多次训练模型,计算出这个参数值时的最低评分、最高评分及平均评分。在第3章介绍学习曲线时,我们使用过这个方法。
问题二的解决方法比较简单,把代码再优化一下,能处理多个参数组合即可。
所幸,我们不需要实现这些代码。scikit-learn在sklearn.model_selection包里提供了大量的模型选择和评估的工具供我们使用。针对以上问题,可以使用GridSearchCV类来解决。
集合算法
集合算法(Ensemble)是一种元算法(Meta-algorithm),它利用统计学采样原理,训练出成百上千个不同的算法模型。当需要预测一个新样本时,使用这些模型分别对这个样本进行预测,然后采用少数服从多数原则,决定新样本的类别。集合算法可以有效地解决过拟合问题。在scikit-learn里,所有的集合算法都实现在 sklearn.ensemble
包里。
- 自助聚合算法Bagging
- 正向激励算法boosting
随机森林(待补充)
在前面的决策当中我们提到,一个标准的决策树会根据每维特征对预测结果的影响程度进行排序,进而决定不同的特征从上至下构建分裂节点的顺序,如此以来,所有在随机森林中的决策树都会受这一策略影响而构建的完全一致,从而丧失的多样性。所以在随机森林分类器的构建过程中,每一棵决策树都会放弃这一固定的排序算法,转而随机选取特征。
在scikit-learn里,由RandomForestClassifier和RandomForestRegressor分别实现随机森林的分类和回归算法。
ExtraTrees算法
随机森林在构建决策树的过程中,会使用信息熵(或基尼不纯度),然后选择信息增益最大的特征来进行分裂。而ExtraTrees是直接从这些特征里随机选择一个特征来分裂,从而避免了过拟合问题。
在scikit-learn里,由ExtraTreesClassifier和ExtraTreesRegressor分别实现ExtraTrees分类和回归算法。
支持向量机
-
一句话总结支持向量机算法的最大特点。
SVM的最大特点是能构造出最大间距的决策边界,从而提高分类算法的鲁棒性。
-
什么是松弛系数,它有什么作用?
引入松弛系数类似于逻辑回归算法里的成本函数引入正则项,目的都是为了纠正过拟合问题,让支持向量机对噪声数据有更强的适应性。当出现一些违反大间距规则的噪声样本时,仍然希望我们的分隔超平面是原来的样子,这就是松弛系数的作用。
-
一句话总结什么是核函数?什么是相似性函数?两者有什么关系?
-
常用的核函数有哪些?分别有什么特点?
核函数
实例:乳腺癌检测
从图中可以看出,二阶多项式核函数的拟合效果更好。平均交叉验证数据集评分可达0.950,最高时达到0.975。运行段示例代码的读者需要注意,二阶多项式核函数计算代价很高,在笔者的Macbook Pro上,运行了数分钟之久。
在第6章中,我们使用逻辑回归算法来处理乳腺癌检测问题时,使用二队多项式增加特征,同时使用L1范数作为正则项,其拟合效果比这里的支持向量机效果好。更重要的是,逻辑回归算法的运算效率远远高于二阶多项式核函数的支持向量机算法。当然,这里的支持向量机算法的效果还是比使用L2范数作为正则项的逻辑回归算法好的。由此可见,模型选择和模型参数调优,在工程实践中有着非常重要的作用的。
PCA算法
主成分分析法,它是一种维数约减(Dimensionality Reduction)算法,即把高维度数据在损失最小的情况下转换为低维度数据的算法。显然,PCA可以用来对数据进行压缩,可以在可控的失真范围内提高运算速度。
是否可以用PCA算法来解决过拟合问题?为什么?
怎么样确定PCA算法时的k参数?
实例:人脸识别
想想看,我们总共有4096个特征,可是数据集大小才400个,比特征个数还少,而且我们还需要把数据集分出20%来作为测试数据集,这样训练数据集就更小了。这样的状况下,模型根本无法进行准确地训练和预测。
解决上述问题的一个办法是使用PCA来给数据降维,只选择前k个最重要的特征。问题来了,选择多少个特征合适呢?即怎么确定k的值?
在scikit-learn里,可以从PCA模型的explained_variance_ratio_变量里获取经PCA处理后的数据还原率。这是一个数组,所有元素求和即可知道我们选择的k值的数据还原率,数值越大说明失真越小,随着k值的增大,数值会无限接近于1。
利用这一特性,可以让k取值10~300之间,每隔30进行一次取样。在所有的k值样本下,计算经过PCA算法处理后的数据还原率。然后根据数据还原率要求,来确定合理的k值。针对我们的情况,选择失真度小于5%,即PCA处理后能保留95%的原数据信息。
- 点赞
- 收藏
- 关注作者
评论(0)