机器学习复习笔记之模型构建和优化过程
由ypyu创建,最终由ypyu 被浏览 68 用户
机器学习流水线
预处理过程
探索数据集、数据预处理、特征工程。
——见相关笔记
构建模型过程
包括构建模型的预处理,选择算法与模型优化,而模型优化涉及评估验证和调参。
预测过程
系统设计指导原则
快速搭建你的第一个系统,然后开始迭代。而不是妄图一口吃成个胖子,一下就能搭建出复杂而完美的系统。
不断地验证,不断地调试,不要妄图一下就写出一个完美的模型,而宁愿一开始比较粗糙,比较简单,但迅速实现,然后一步一步的误差分析和优化而使它变好。
构建模型的预处理过程
1、提取特征集和标签
labels = data['income']
features = data.drop('income', axis = 1)
2、切分训练集、验证集(开发集)、测试集
如果像一些kaggle竞赛之类的,别人已经为你切分了训练集和测试集,只给你训练集训练,那这时只需切分一次即可,将训练集再切分为训练集和验证集。但如果没有,那就可能需要切分两次。第一次切分一般就是留出法切出测试集;第二次切分则有两种方法:留出法和交叉验证法。
2.1 train、valid(dev)、test的区别
训练集用于训练模型(模型的学习),验证集用于调参(模型的优化)、测试集用于实践(模型的应用)
训练集 → 题解大全
验证集 → 模拟考试
测试集 → 高考
2.2 测试集大小的设置
一是取决于你拥有的数据量的大小,数据量越大,比例可以越小。
二是取决于对系统性能是否有要有置信度很高的评估,越靠谱的评估需要测试集越大。
小数据时代:6:2:2
百万数据,98:1:1
更多:99.5:0.25:0.25
2.3 具体切分方法
(1)留出法
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(features, labels, test_size = 0.2, random_state = 42)
(2)交叉验证
——充分利用数据集
kf = KFold(n_splits=2)
将 shuffle(洗牌) 参数设置为 true。以防止可能产生的问题:一类数据大都被归入了训练集,另一类数据大都被归入了测试集,因此导致算法的准确度很低。(比如说一堆邮件分别是甲和乙写的,而我们把甲写的都划入了训练集,把乙写的都划入了测试集)
设置评估指标
无论是选择不同的算法,还是不同的参数(调参),都需要基于一个评估指标。
选择不同评估指标,具体取决于我们要尝试解决的问题,比如分类问题和回归问题就有不同的评估指标。又比如有些数据存在样本不平衡问题, 有些问题旨在识别某一类数据,这时用简单的准确度(accuracy)指标就没有意义(天真预测器的对比)。
分类问题
true和false:真和假;代表你的判断是否正确。
positive和negative:阳、正和阴、负;代表你判断的类别。
**(1)查准率(命中率):**precision
precision=真正例/(真正例+假正例)——多做多错、少做少错
——我们只统计你选P并正确的题除以你选P的题,以此来判断你的分数。看你是否对某一类一击即命中。
适合:倾斜数据集。我们一般把数量较少的样本叫阳性样本(正例,positive),一般情况下我们也只关心阳性样本的预测结果。最常见的倾斜数据例子是癌症检查,得了癌症的不幸的人就是阳性样本,相对于健康的大众,他们是稀少的存在。
**(2)查全率(召回率、识别率):**recall
recall=真正例/(真正例+假负例)——宁可错杀、不可放过
——我们只统计你选P并正确的题除以正确答案应该是P的题,以此来判断你的分数。看你是否对把某一类全部识别出来。
适合:假阳性和假阴性这两种错误的重要性不同的场景。比如边境的安检会犯两种错误,不是恐怖分子却当作恐怖分子审讯(假阴),是恐怖分子却当作正常人放行(假阳),无疑假阳的错误更严重。再比如统计学中,第一类错误就是假阳性错误,即原假设本为真,却错误地拒绝,如前所述,这里的阳性(或正例)不是正确或错误、肯定或否定,而是我们所更关心的那个结果,拒绝原假设就是我们更关心的,因为这样才能证明备择假设正确。
(3)F分数
F分数将两个指标结合在一起变成一个指标,同时考虑精确率和召回率,叫做单一数字评估指标或单实数评估指标。
$F_{\beta}=\frac{(1+\beta^{2})\times p\times r}{(\beta^{2}\times p)+r}=\frac{1+\beta^{2}}{\frac{\beta^{2}}{r}+\frac{1}{p}}$
——其实就是两个指标的加权调和平均数,权重β越大表示召回率越重要,等于1时就是F1分数。
from sklearn.metrics import fbeta_score, accuracy_score
results = {}
results['acc'] = accuracy_score(y_true,predictions)
results['f'] = fbeta_score(y_true,predictions,beta=0.5)
(4)ROC 与 AUC
ROC(Receiver Operating Characteristic):接收者操作特征曲线。
AUC(Area Under Curve):ROC曲线下的面积。
为什么要使用 ROC和AUC:在实际的数据集中经常会出现类不平衡(class imbalance)现象,即负样本比正样本多很多(或者相反),而且测试数据中的正负样本的分布也可能随着时间变化。当测试集中的正负样本的分布变化的时候,其性能得分就会有很大的变动(想想如果是瞎蒙,全猜A或全猜B的情况),但ROC曲线能够保持不变。
ROC曲线的横坐标为FPR(false positive rate),纵坐标为TPR(true positive rate)。
考虑ROC曲线图中的四个点和一条线:
第一个点(0,1),即FPR=0, TPR=1,也意味着TNR=1,FNR=0,没有分类false的,所有的分类均正确。
第二个点(1,0),即FPR=1,TPR=0,同理这意味着所有分类均错误。
第三个点(0,0),即FPR=TPR=0,意味着TNR=FNR=1,该分类器预测所有的样本都为负样本(N)。
第四个点(1,1),该分类器预测所有的样本都为正样本(P)。
基于以上分析,可以说:ROC曲线越接近左上角,该分类器的性能越好。
AUC是ROC曲线下的面积,显然数值不大于1。又由于ROC曲线一般都处于y=x这条直线的上方,所以AUC的取值范围一般在0.5和1之间。
使用AUC值作为评价标准是因为很多时候ROC曲线只是一个曲线,当两条曲线比较接近时不容易比较,而AUC作为一个数值,可以更直接的比较大小。
回归问题
(1)平均绝对误差(Mean Absolute Error):MAE=
$\frac{1}{m}\sum_{i=1}^{m}{|y_{predict}^{(i)}-y_{true}^{(i)}|}$
——有关平均绝对误差和如何在 sklearn 中使用它的更多信息,查看此处。
(2)均方误差(Mean Square Error):MSE=
$\frac{1}{m}\sum_{i=1}^{m}{(y_{predict}^{(i)}-y_{true}^{(i)})^{2}}$
——误差平方和(Sum of Squares for Error,SSE)=MSE×m
(3)均方根误差(Root Mean Square Error):RMSE=√MSE
(4)均方根百分比误差(Root Mean Square Percentage Error ):RMSPE
——Kaggle比赛Rossmann Store Sales项目即用RMSPE作为评估销售预测的误差。就是在RMSE的基础上,令真实值与预测值之差再除以真实值,形成一个比例。
def metric_RMSPE(y_true, y_predict):
y1 = np.array(y_predict)
y2 = np.array(y_true)
n = len(y_true)
temp = np.square((y1 - y2)/y2).sum()
score = np.sqrt(temp/n)
return score
(5)R2分数=SSR/SST=1-SSE/SST
——指模型里可解释内容的占比。
- 残差或误差平方和(预测值/估计值与真实值)
SSE(Sum of Squares for Error) = RSS (residual sum of squares)
- 总的平方和(真实值与均值)
SST(Sum of Squares for Total) = TSS(total sum of squares)
- 回归平方和(预测值与均值)
SSR(Sum of Squares for Regression) = ESS (explained sum of squares)
鉴于R^2局限性:当给模型增加自变量时,决定系数也随之逐步增大,但这种增大是因为自变量个数的增多引起的,而不一定真的是模型的拟合度变好。
所以有调整后的R2=1-(SSE/dfE)/(SST/dfT)
**区别:**R^2相当于是对所有的数据都会有一个相同的比较标准。也就是说你得到一个值0.9999,那就非常好(当然对不同的应用你对好的定义可能会不一样,比如某些你觉得0.6就够了,某些你要0.8)。而MAE和MSE就是数据相关了,范围可以非常大,你单纯根据一个值完全不知道效果怎么样。
相比于 R^2 作为拟合度的评价, RMSPE 更贴近误差的概念。而相比于 MSE 和 RMSE, RMSPE 计算的是一个误差率,这样就避免了真实值之间大小的不同而对误差产生的影响。 RMSPE 的缺点是,如果预测值是真实值的两倍以上,则 RMSPE 取值可能就会非常大,失去了评估的意义。所以理论上, RMSPE的取值范围是 0 到正无穷
选择算法
1、kaggle调查:最常使用的算法排名
logistic回归基于经典的回归理论,最大的优点是结果可解释,速度快,操作还简单(不用调参),所以在工业界应用最为广泛(第1)。
DT的输出结果可以进行可视化,也易于理解,在特征不多时效果也很好,应用也很多。(第2)
DT有稳定性差、易过拟合等问题,而各种基于树的算法不同程度解决了这些问题,成为在传统机器学习中比较强大的算法。(RF第3,集成方法第6,GBM第8)
神经网络、深度学习随着大数据的兴起,在CV/NLP等领域应用越来越广泛(NN第4,CNN第9,RNN第10)。
贝叶斯模型是与别的不同的生成式模型,有其自己的应用领域(第5)。
SVM的应用与神经网络、深度学习有所重合,在后者的冲击下有些失势(第7)。
HMM(隐马尔可夫模型)的应用与RNN有些重合(第13)
2、监督学习的算法选择思路
(1)看问题类型:是分类还是回归?
(2)看准确度要求
(3)看处理速度要求
(4)看调参难度
调参容易:logistic回归(不需调参,除非要正则化)
调参困难:XGBoost、神经网络及深度学习
(5)是否有局部最优问题
局部最优问题:神经网络、DT
无局部最优问题:logistic回归、SVM、NB
(6)是否易于理解、解释
简单:logistic回归、NB、DT
复杂:神经网络及深度学习(黑箱)
(7)特征数量
适合多特征:NB、神经网络及深度学习
适合少特征:DT(多特征容易过拟合)、RF(也只有几十维)
(8)数据规模
要大数据:神经网络、DT、集成学习
要小数据:logistic回归、SVM、NB
(9)是否容易过拟合
容易过拟合:DT、神经网络
不易过拟合:logistic回归、NB、RF
(10)是否需要特征缩放
需要缩放的:logistic回归、SVM、K均值聚类
不需要缩放的:决策树、NB
(11)缺失值较多
抗缺失能力强:DT、NB(?)
抗缺失能力弱:SVM
(12)噪声、异常值较多
抗干扰能力强:NB、神经网络
抗干扰能力弱:SVM、DT
3、其他参考:
- Choosing a Machine Learning Classifier :Edwin Chen所做的概述,短小易懂,可读性强。
- scikit-learn的“机器学习导图” :选择“正确”的估计器(estimator)。
- Machine Learning Done Wrong :深思熟虑的建议,避免在机器学习中掉进常见的坑,有些建议涉及算法的选择。
- Practical machine learning tricks from the KDD 2011 best industry paper :较上一项更高级的建议。
- An Empirical Comparison of Supervised Learning Algorithms :发表于2006年的研究论文。
模型优化(调参)
模型优化实际就是一个调参的过程,在使用各种模型优化策略时,不可避免的需要设定各种超参数,通过设置一个最佳超参数达到模型的最佳性能。
1、模型优化的目标:降低偏差与方差,避免欠拟合和过拟合
我们希望最优的模型不仅可以很好地拟合训练数据,而且有较好的泛化能力,也就是说训练误差和泛化误差都小,即同时具有较小的偏差(bias)和方差(variance)。偏差过大就是欠拟合,说明模型并没有很好地学到数据的信息;方差过大就是过拟合,说明模型并没有把在训练集数据上学到的东西很好地用到测试集上。
2、如何衡量偏差和方差/如何衡量
法(1):设定一个最优误差(贝叶斯误差),将最优误差、训练集误差、验证集误差三者进行对比。
比如三者分别为1/2/7,妥妥的方差过大;比如三者为1/10/11,妥妥的偏差过大。
——一般将人类水平作为贝叶斯误差,否则就需要自己手动设置一个基准(benchmark)。
法(2):通过学习曲线(准确率和数据规模的关系)和模型复杂度曲线(准确率和模型复杂度的关系)来看。
from sklearn.learning_curve import learning_curve # sklearn 0.17
from sklearn.model_selection import learning_curve # sklearn 0.18
learning_curve(estimator, X, y, cv=cv, n_jobs=n_jobs, train_sizes=train_sizes)
参数说明:
estimator是我们正在用来预测的模型,cv是交叉验证生成器,例如KFold();
train_sizes是依次用多少数量的训练数据来生成曲线。比如 train_sizes = np.linspace(.1,1.0,10),就是生成[ 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.]的数组。这里是一个比例。比如你的总训练集是1000,kf = KFold(n_splits=3),那么就是把总训练数据分三份,三分之一为验证集,三分之二(666)为训练集,那么就是从0.1*666到1*666为横轴的刻度。
这个参数的意义:画学习曲线时,一口一口喂数据,喂一口,得到score,画点,最后连点成线。既然这样,怎么决定这个数组的数量呢,你中意,你喜欢光滑点,大口喂,喜欢波澜点,小口喂。
scoring参数设置一个评分函数(比如accuracy和F1)
学习曲线
模型复杂度曲线
3、解决方法
(1)降低偏差减少欠拟合
更多的特征、不同的模型和参数(复杂度升高)
(2)降低方差减小过拟合
更多的数据、不同的模型和参数(复杂度降低)、正则化
法1:正则化
即将前面一直说的代价函数(损失函数、风险函数)中加入一个正则化项。以线性回归为例:
$J(w)=\frac{1}{2m}\sum_{i=1}^{m}{L(f(x^{(i)}),y^{(i)})}+\frac{1}{2m}\lambda||w||_{2}^{2}$
这时的代价函数又叫结构风险函数,前面的部分叫做经验风险或经验损失(机器学习的训练过程类比人类的经验式学习)。λ叫做正则化参数,||w||是范数,其下标为2代表是L2范数(欧几里得距离),所以叫L2正则化。(加平方为了消去根号,便于计算,并且增大惩罚力度)
而L1正则化用曼哈顿距离,即绝对值。用L1可能造成有些w为0的情况(造成稀疏)。
神经网络中,多了层数的概念,正则化项略有不同,对于每一层都有一个参数矩阵:
第l层有n[l]个节点就需要n[l]个方程,每个方程都有n[l-1]个参数(对应上一层的输出)。
上式叫做弗罗贝尼乌斯范数(Frobenius norm)。
带正则化项的目标函数进行梯度下降,相当于每次迭代都比原来减少的更多,所以L2正则化叫又权重衰减。
无λ不能起到正则化作用,λ过大则会导致w过小(即压缩权重,但压缩过大会导致很多w被设置为0,可理解为删掉神经网络中的部分node,使得神经网络过于简单),倾向于欠拟合。所以找到合适的中间值,才能实现 just right。
法2:调参
-
**手动调参:**参考经验、其他人的成果。
-
使用sklearn中网格调参,暴力搜索最佳参数组合
from sklearn.model_selection import GridSearchCV from sklearn.metrics import make_scorer
建立模型
clf =
以字典格式创建待调参数的列表
parameters = {}
自定义评估标准(可选)
scorer = make_scorer(fbeta_score,beta=0.5)
交叉验证(可选)
cross_validator = KFold()
创建网格搜索器
grid_obj = GridSearchCV(clf, parameters, scoring=scorer, cv=cross_validator)
用训练数据拟合以找到最佳参数
grid_obj.fit(X_train, y_train)
获取具有最佳参数的模型
best_reg = grid_obj.best_estimator_
用此模型预测结果
val_predictions = best_clf.predict(X_val)
因为 sklearn 中 GridSearchCV 遍历所有给定的参数组合。所以内存占用高,运算速度慢。在实践中还有 RandomizedSearchCV 也可以使用,并且效果还不错。可以参考这篇文章和论文。
4、深度学习的优化策略
——更多神经网络的优化策略见相关笔记
对于传统机器学习算法,常常面临方差和偏差两者的权衡(二者负相关),但对于深度神经网络算法和大数据,我们可能做到降低一方的同时不影响另一方(这可能是深度学习对传统监督学习的其中一个提升)。
这就是所谓**正交化(orthogonalization)**的优化策略。
——正交意味着互成90度,比如电视机,一个按钮对应一个功能,互不影响。
但是,深度学习虽然可以很多方法来优化模型,但同时也有代价,就是很多方法都会附带着超参数,所以用的优化方法越多,需要调的超参数越多。
吴恩达推荐一个系统化的步骤,先通过增加网络的层数(深度)、增加训练时长以降低偏差,再通过增加数据、正则化等方式降低方差,然后不断循环这个过程。
比如你希望有一组独立的方法可以分别提升训练集、验证集(开发集)、测试集上的表现,而能够互不影响,这样就不会出现类似需要平衡偏差和方差的情况了。
提升训练集表现:更大的神经网络、优化算法
提升验证集表现:更大的训练集、正则化
提升测试集表现:更大的验证集
但像early stopping就会同时影响训练集和验证集,这种方法就没那么正交化了。
5、其他参考
维基百科 https://en.wikipedia.org/wiki/Bias%E2%80%93variance_tradeoff
华盛顿大学机器学习课程 https://www.coursera.org/learn/ml-regression/home/week/3
Scott Fortmann-Roe 撰写的**这篇文章**。
\