当前位置: 首页 > 科技观察

机器学习入门必看|使用scikit-learn构建模型的通用模板

时间:2023-03-16 17:09:17 科技观察

构建自己的机器学习模型只需要两步:确定你需要解决什么类型的问题并知道它是什么采取解决这类问题的相应算法。只需要从skicit-learn中调用相应的算法来构建模型即可。是的!在机器学习领域,如果只是抱着体验机器学习的心态,实现起来就是这么简单。第一步很好解决常见的问题类型,只有分类、回归、聚类三种。明确具体问题对应的类型也很简单。例如,如果你需要从输入数据中得到一个分类变量,它就是一个分类问题。分为两类是二分类问题,分为两类以上是多分类问题。常见的有:判断一封邮件是否是垃圾邮件,根据图片区分图片是猫还是狗等等。如果需要从输入数据中得到一个特定的连续值,那就是回归问题。例如:预测某个区域的房价等。常用的分类和回归算法包括:SVM(支持向量机)、xgboost、KNN、LR算法、SGD(随机梯度下降算法)、Bayes(贝叶斯估计)和随机森林。大多数这些算法既可以解决分类问题,也可以解决回归问题。如果你的数据集没有对应的属性标签,你需要做的是探索这组样本在空间上的分布,比如分析哪些样本比较近,哪些样本相距较远,属于聚类问题。常用的聚类算法是k-means算法。在本文中,我们主要解决第二步:通过skicit-learn构建模型。给大家说说一套让你笑掉大牙的通用模型搭建模板。只要是scikit-learn实现的算法都可以通过这种方式快速调用。牢记这三个通用模板,您可以轻松构建自己的机器学习模型。前期工作在介绍通用模板之前,为了对这三个模板有更深入的了解,我们加载一个鸢尾花(Iris)数据集作为应用通用模板的一个小例子。Iris数据集在之前的文章中已经提到过。已经说过很多次了,这里不再赘述。这是一个典型的多分类问题。加载步骤如下:1.加载数据集由于原始数据集包含很多空值,类别特征使用英文名称来表示每朵花的名称,因此我们还需要将它们转换为数字。在scikit-learn下的datasets子包中,还自带了一个鸢尾花数据集。这个数据集和原始数据集的区别在于,scikit-learn已经帮我们提前处理了空值等问题,可以直接输入到模型中。培训。所以为了方便,我们直接使用scikit-learn数据集。加载方式如下:fromsklearn.datasetsimportload_irisdata=load_iris()x=data.datay=data.targetx取值如下,可以看到scikit-learn将数据集去掉空值后放入数组中,所以x是一个(150,4)数组,保存了150条数据的4个特征:array([[5.1,3.5,1.4,0.2],[4.9,3.,1.4,0.2],[4.7,3.2,1.3,0.2],[4.6,3.1,1.5,0.2],[5.,3.6,1.4,0.2],[5.4,3.9,1.7,0.4],[4.6,3.4,1.4,0.3],[5.,3.4,1.5,0.2],[4.4,2.9,1.4,0.2],[4.9,3.1,1.5,0.1],[5.4,3.7,1.5,0.2],[4.8,3.4,1.6,0.2],[4.8,3.,1.4,0.1],[4.3,3.,1.1,0.1],…………y值如下,共150行,其中0、1、2代表三种花:array([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2])2.DatasetsplittingDatasetsplitting是验证模型在训练集和测试集是否过拟合。使用train_test_split的目的是保证测试集从数据集中平均分割。在这里,只需取10%的数据集并将其用作测试集。fromsklearn.model_selectionimporttrain_test_splittrain_x,test_x,train_y,test_y=train_test_split(x,y,test_size=0.1,random_state=0)万能模板V1.0版帮助你快速搭建基础算法模型不同的算法只是改个名字,而模型参数不同。有了这个万能模板,接下来就是简单的复制粘贴改名字了:而在scikit-learn中,每个包的位置都是有规律的,比如:randomforest在integratedlearning文件夹下。模板1.0的应用案例1.建立SVM分类模型通过查阅资料,我们知道svm算法在scikit-learn.svm.SVC下,所以:算法位置填写:svm算法名称:SVC()模型名称自己,这里我们调用svm_model应用模板得到程序如下:)accuracy1=accuracy_yscore(,pred1)print('训练集准确率:%.4f'%accuracy1)pred2=svm_model.predict(test_x)accuracy2=accuracy_score(test_y,pred2)print('测试集准确率:%.4f'%accuracy2)输出:训练集上的准确度:0.9810测试集上的准确度:0.97782。构建LR分类模型也是如此。在sklearn.linear_model.LogisticRegression下找到LR算法,于是:算法所在位置填写:linear_model算法名称填写:LogisticRegression模型名称为:lr_model。程序如下:应用模板得到程序如下:#LogisticRegressionclassifierfromsklearn.linear_modelimportLogisticRegressionfromsklearn.metricsimportaccuracy_score#Scoringfunctionevaluateswithaccuracylr_model=LogisticRegression()lr_model.fit(train_x,train_y)pred1=lr_model.predict(train_x)accuracy1=accuracy_score(train_y,pred1)print('训练集上的准确率:%.4f'%accuracy1)pred2=lr_model.predict(test_x)accuracy2=accuracy_score(test_y,pred2)print('onthetestsetAccuracyon:%.4f'%accuracy2)Output:Accuracyonthetrainingset:0.9429Accuracyonthetestset:0.88893,在sklearn.ensemble.RandomForestClassifier下建立随机森林分类模型RandomForest算法,不错不错,现在你应该可以自己写了。这是对本文的一个小测试。欢迎在评论区写下你的答案。UniversalTemplateV2.0加入交叉验证,让算法模型评估更科学。在1.0版本的模板中,当你多次运行同一个程序时,你会发现每次运行得到的准确率是不一样的,但是都在一定的范围内浮动,这是因为在进入之前会选择数据模型,每次训练时数据进入模型的顺序都是不同的。所以即使是同一个程序,模型最终的表现也会有好有坏。更糟糕的是,在某些情况下,调整参数设置以在训练集上实现最佳性能的模型可能会在测试集上过度拟合。这时候我们在训练集上得到的分数并不能有效反映模型的泛化性能。为了解决以上两个问题,还应该在训练集上划分一个验证集,结合交叉验证来解决。首先将不参与训练的验证集划分到训练集中,待模型训练完成后才对模型进行评估,再对测试集进行最终评估。但这大大减少了可供模型学习的样本数量,因此需要使用交叉验证进行更多次训练。比如最常用的k折交叉验证如下图所示,主要是将训练集分成k个更小的集合。然后用k-1个训练集子集作为训练集训练模型,用剩下的1个训练集子集作为验证集进行模型验证。这需要k次训练,最终在训练集上的评价分数是所有训练结果评价分数的平均值。这样一方面可以让训练集中的所有数据都参与训练,另一方面可以通过多次计算得到更具代表性的分数。唯一的缺点是计算成本非常高,增加了k倍的计算量。原则是这样,但理想很丰满,现实很骨气。当我自己意识到的时候,摆在我面前的是一个很大的问题:如何将训练集平均分成K份?这个问题大家不用想太多,别忘了,我们现在是站在巨人的肩膀上,scikit-learn把优秀数学家想到的偶分法和程序员的智慧融合到了cross_val_score()this函数中,只需要调用该函数,不需要考虑拆分算法,也不需要写for循环进行循环训练。万能模板2.0是这样的:将模型、数据、划分验证集的个数输入到函数中,函数会自动执行上述过程。在寻找准确率时,我们可以简单地输出平均准确率:#输出准确率的平均值#print("Accuracyonthetrainingset:%0.2f"%scores1.mean())但是由于我们进行了交叉验证,之后做了这么多计算,只求一个平均值还是有点浪费。可以使用以下代码求准确率的置信度:#输出准确率的平均值和置信区间print("OnthetrainingsetAverageaccuracy:%0.2f(+/-%0.2f)"%(scores2.mean(),scores2.std()*2))Template2.0应用案例:1.构建SVM分类模型的流程如下:###svmclassifierfromsklearn.model_selectionimportcross_val_scorefromsklearn.svmimportSVCsvm_model=SVC()svm_model.fit(train_x,train_y)scores1=cross_val_score(svm_model,train_x,train_y,cv=5,scoring='accuracy')均值和置信区间print("训练集的准确度:%0.2f(+/-%0.2f)"%(scores1.mean(),scores1.std()*2))scores2=cross_val_score(svm_model,test_x,test_y,cv=5,scoring='accuracy')#输出均值和置信度精度间隔print("测试集的平均精度:%0.2f(+/-%0.2f)"%(scores2.mean(),scores2.std()*2))print(scores1)print(scores2)输出:训练集的准确度:0.97(+/-0.08)测试集的平均精度:0.91(+/-0.10)[1.1.1.0.90476190.94736842][1.0.888888890.888888890.8750.875]2.构建LR分类模型#LogisticRegressionclassifierfromsklearn.model_selectionimportcross_val_scorefromsklearn.linear_modelimportLogisticRegressionlr_model=LogisticRegression()lr_model.fit(train_x,train_y)scores1=cross_val_score(lr_model,train_x,train_y,cv=5,scoring='accuracy')#输出精度的均值和置信区间打印("训练集的准确度:%0.2f(+/-%0.2f)"%(scores1.mean(),scores1.std()*2))scores2=cross_val_score(lr_model,test_x,test_y,cv=5,scoring='accuracy')#输出精度的均值和置信区间print("测试集上的平均精度:%0.2f(+/-%0.2f)"%(scores2.mean(),scores2.std()*2))print(scores1)print(scores2)输出:训练集准确度:0.94(+/-0.07)测试集平均准确度:0.84(+/-0.14)[0.909090911.0.952380950.90476190.94736842][0.909090910.888888890.888888890.750.75]随机森林还是保留给小测试注意:如果想一次评估多个指标,也可以使用cross_validate()函数,可以输入多个评估指标一次。UniversalTemplateV3.0版本参数调优使算法性能更佳。算法的默认参数用于训练上面的模型。不同数据集适用的参数必然不同。自己设计算法是不可能的。只能这样调,调参是广大算法工程师最后的尊严。再说了,如果不调整参数就去做算法,岂不是有辱算法工程师在世界上有名的“炼金工程师”的名声?scikit-learn也为不同的算法提供了不同的参数,可以自己调整。说的详细点,可以写好几篇文章。本文的目的是构建一个通用的算法框架构建模板。因此,这里仅介绍一种通用的自动调参方法。首先要明确的是scikit-learn提供了algorithm().get_params()方法来查看各个算法可以调整的参数。比如我们要查看SVM分类器算法可以调整的参数,可以:SVC()。get_params()的输出是SVM算法可以调整的参数和系统默认的参数值。{'C':1.0,'cache_size':200,'class_weight':None,'coef0':0.0,'decision_function_shape':'ovr','degree':3,'gamma':'auto','kernel':'rbf','max_iter':-1,'probability':False,'random_state':None,'shrinking':True,'tol':0.001,'verbose':False}然后,我们就可以引出我们的V3.0版本的通用模板。参数的形式如下:程序会依次测试这些参数的组合效果,实现时无需费力。至此,感谢大家编写了scikit-learn这样方便的机器学习包。突然,我想起了一句话:世上没有安静的时光,只因有人为你背负重担。看到这里,可能有人会有疑惑:为什么要用列表、字典、列表的三级嵌套方式呢?params不能直接用字典的形式吗?答案是:好,但不好。这就是列表的作用,保证每次只调整列表中一个字典中的参数。运行后best_model就是我们得到的最优模型,可以用来做预测。当然best_model还有很多有用的属性:best_model.cv_results_:可以查看不同参数下的评估结果。best_model.param_:获取模型的最优参数best_model.best_score_:获取model3.0应用案例实现SVM分类器的最终评分结果模板###1,svmclassifierfromsklearn.model_selectionimportcross_val_score,GridSearchCVfromsklearn.svmimportSVCsvm_model=SVC()params=[{'kernel':['linear'],'C':[1,10,100,100]},{'kernel':['poly'],'C':[1],'degree':[2,3]},{'kernel':['rbf'],'C':[1,10,100,100],'gamma':[1,0.1,0.01,0.001]}]best_model=GridSearchCV(svm_model,param_grid=params,cv=5,scoring='accuracy')best_model.fit(train_x,train_y)1)查看最好成绩:best_model.best_score_output:0.97142857142857142)查看最好参数:best_model.best_params_Output:{'C':1,'kernel':'linear'}3)查看最优模型的所有参数:best_model.best_estimator_这个函数会显示没有调参的参数,方便整体查看模型的参数。4)查看各个参数的交叉验证结果:best_model.cv_results_注意:1、之前的版本是best_model.grid_scores_,现在已经去掉了。2、该函数输出的数据很多,不方便查看。一般在实际使用中是不会用到的。如果计算资源充足,一般采用第三种通用公式。如果,为了节省计算资源和尽快计算出结果,也会采用后面介绍的手动调参的方法。当然,为了说明万能模板的使用,本文将所有算法都在鸢尾花数据集上实现。在实际应用中,如果项目时间紧迫,根据自己的需求和数据量选择合适的算法即可。.具体如何选择,scikit-learn官方很贴心的画了一张图,方便大家根据数据量和算法类型选择合适的模型。此图推荐收藏: