本文是【统计师的Python日记】第12天的日记
回顾一下:
第1天学习了Python的基本页面、操作,以及几种主要的容器类型。
第2天学习了python的函数、循环和条件、类。
第3天了解了Numpy这个工具库。
第4、5两天掌握了Pandas这个库的基本用法。
第6天学习了数据的合并堆叠。
第7天开始学习数据清洗,着手学会了重复值删除、异常值处理、替换、创建哑变量等技能。
第8天接着学习数据清洗,一些常见的数据处理技巧,如分列、去除空白等被我一一攻破
第9天学习了正则表达式处理文本数据
第10天学习了数据的聚合操作、数据透视表pivot_table()方法、交叉表crosstab
第11天学习了class类的概念以及如何写一个类
(历史文章因为之前在其他平台上发表,所以头条这里发布有些问题,后续会在搬过来)
今天将带来第12天的学习日记,开始学习Python的机器学习库:Scikit-learn(这个系列会不断连载,建议关注哦~)。本文会先认识一下 sklearn 这个库,再根据建模流程,学习一下 sklearn 的各个模块的使用。
目录如下:
前言
一、初识 sklearn
二、sklearn 的建模流程
1. 数据导入
2. 数据处理
(1)划分训练集和测试集
(2)数据清洗
3. 特征工程
4. 模型调参/选择
5. 模型测试和评价
6. 模型保存和调用
三、sklearn 建模流程总结
前言
前面学习了很多 Python 的数据基本操作,应付一个 project 前期的数据清洗、描述分析已然足够。今天开始要学习数据工程中的重头戏——数据建模。
用 Python 完成一个模型的构建,比较快的可以有三种方法:
① 第一种是完全按照计算逻辑写代码,比如 logistic 回归模型,你可以这么写:
(具体可以看这里:造出一艘logistic模型 | 【logistic从生产到使用】(下))
② 第二种是用最近很火的 tensorflow 开源库,同样的 logistic 回归,简洁一点的话可以这么写:
③ 第三种是用机器学习库 sklearn,logistic 回归我们只用这么写:
其他还有很多库就不说了,这三种中,第二种或者第三种显然是合理的选择。
- tensorflow 是一种深度学习库,有很高的自由度,需要自己实现算法。适合数据量较大、一般需要GPU加速的运算。
- 而sklearn 是通用机器学习库,里面已经包含了很多现成的深度学习算法、机器学习模型,以及数据预处理和特征工程。封装的高度抽象化,简单易用,适合中小型的机器学习项目,那种数据量不大、CPU上就可以完成的运算。
所以,对于初学者来说,sklearn是首选,因为它不仅封装了大量的机器学习库,还自带数据集!连学习要用的数据都准备好了,今天,就先学习一下 sklearn。
一、初识sklearn
sklearn 全称是 scikit-learn,它建立在 Numpy 和 matplotlib 的基础上,所以需要注意的是,以下我们介绍的方法,都是适用于 Numpy 数组的哦。现在我们导入这个库:
import sklearn
这个库里面包含了很多数据集、模块和函数,使用某几种函数,可以不用全部导入,用:
from sklearn.模块 import XX
比如:
from sklearn import datasetsfrom sklearn.feature_selection import SelectKBestfrom sklearn.neighbors import KNeighborsClassifier
sklearn 有专门的 feature_selection (特征工程)和 neighbors(近邻算法)模块,下面有对应的方法。如上代码展示:
- feature_selection 模块下面不仅有 SelectKBest(选出K个得分最高的特征),还有chi2(计算每个特征的卡方值)等等;
- neighbors模块下不仅有KNeighborsClassifier(K近邻),还有LocalOutlierFactor(LOF异常检测算法)等算法可供调用。
那么 sklearn 主要有哪些模块,每个模块下面有哪些方法呢?
我数了一下 sklearn 的官方介绍,大概37个模块,包含了差不多500种算法实现(http://scikit-learn.org/stable/modules/classes.html)。
这里列出了我们建模常用的一些模块和算法:
其实,只要学习一种方法的典型流程,其他的方法查查资料就可以很快上手。现在我们就以内部数据集为例,用 sklearn 学习一遍整个建模的流程。
二、sklearn 的建模流程
1. 数据导入
(1)导入自带数据
我们要导入最经典的sklearn自带「鸢尾花」数据。先了解一下数据结构,首先,导入数据集 load_iris。
#从sklearn的自带datasets中导入load_iris数据集from sklearn.datasets import load_iris iris = load_iris()
看下数据的结构,用keys来看:
print (iris.keys())
结果如下:
dict_keys(['target_names', 'target', 'data', 'feature_names', 'DESCR'])
target 是标签数据,target_names 标签每个类别的意义,data 是特征数据, feature_names 是特征列名,DESCR 是关于此数据的一个全面描述。
比如查看 target.name,数据的lable分类:
print(iris.target_names)
可知lable一共有三类。同理 iris.target 就是具体 lable 的数据,iris.data 就是特征的数据了。
print(iris.target)
我们也可以直接来看 DESCR,有更全面的介绍:
print(iris.DESCR)
从描述可以看出,这个数据
- 一共150行;
- label 是鸢尾花的类型,有三类:Setosa/Versicolour/Virginica;
- 共四个特征:萼片sepal的长度和宽度,花瓣petal的长度和宽度,我们就要用这四个特征,来预测鸢尾花的类型。
如果是外部数据,我们可以用 pandas 的read_csv工具来导入,详见 第5天:Pandas,露两手。
2. 数据处理
(1)划分数据集
首先是训练集和测试集的划分,在Python中建模,我们至少需要四个子数据集:
- 训练数据-特征列
- 训练数据-label列
- 测试数据-特征列
- 测试数据-label列
记得在 SAS 中,特征和lable是不需要分开的,在一个数据集中,建模的时候只需要在proc过程中指定出哪一列是 lable 就好。在Python中是需要分开的。
训练数据和测试数据的划分,可以用 train_test_split() 处理,以 iris 数据为例,划分方式如下:
from sklearn.model_selection import train_test_splitX=iris.datay=iris.targetX_train, X_test, y_train, y_test = train_test_split(X,y,test_size=0.3,random_state=0)
test_size 指定测试样本的比例,random_state 是随机数种子,如果random_state的设置是相同的,那么别人运行你的代码就会和你得到完全一样的数据。
(2)数据清洗
现在数据已经导入,用 preprocessing 来做一些预处理:
- 填充缺失值:
from sklearn.preprocessing import Imputerimpt= Imputer(missing_values='NaN', strategy='mean', axis=0)#还可以用"median"、"most_frequent"等来填充 impt.fit(X) impt.transform(X)
- 数据标准化(有时候特征的量纲不一致,或者存在很多异常值,需要进行标准化处理)
from sklearn import preprocessingX_scale = preprocessing.scale(X)
在前面我们也学习了Pandas Dataframe数据的一些预处理方法(详见 第5天:Pandas,露两手 和 第7天:数据清洗(1)),比如:
- 丢弃缺失值:df.dropna()
- 填充缺失值:data.fillna()
等等,可以在Dataframe中处理好,再转换成 Numpy array 数组。
3. 特征工程
我们现在对这四个特征进行筛选,使用 feature_selection 模块的 SelectFpr 来进行选择,选出P值在0.01以下的特征。格式是:
selectFpr(, alpha)
是筛选的统计方法,默认是方差检验的F检验对应p值,此外还可以选chi2(卡方检验)
- f_regression(回归的F检验P值)
- mutal_info_regression(利用特征和标签之间的互信息)
- 等等,具体可查阅官网
from sklearn.feature_selection import SelectFprselectFea=SelectFpr(alpha=0.01)X_train_new = selectFea.fit_transform(X_train, y_train)X_test_new = selectFea.transform(X_test)
这里 fit_transform() 在数据处理环节我们会经常看到,
A.fit_transform()
以及
A.transform()
- A.fit_transform()
是对前面的方法A先进行数据拟合fit,如果A是一个标准化处理的方法,那么fit就可以拟合出数据的均值、方差等参数。这里A是要选择P值,fit就会拟合出每个特征的P值等......再利用这些参数对数据进行transform(),得到最终我们要的数据。
- A.transform()
按照上面说的,这个就是直接对已经fit过的进行transform了。通常train的数据既要fit又要transform,测试数据只要也必须要transform。“只要”是因为已经fit过了,就用测试集fit的结果,“必须要”是测试集的特征选择必须要和训练集的选择结果一致。
特征选择的时候,我们通常不会那么粗暴,还会综合考虑特征的IV值、WOE分等,网上很多代码,推荐学习:https://www.sohu.com/a/227312722_479788
4. 模型调参/选择
选择完特征,我们需要选择一个合适的模型。思路是:
先指定若干分类模型,每个模型在测试数据集上进行参数的【网格搜索+交叉验证】,选出表现最好的模型和其参数。
首先,导入一些待验证的分类模型:
#MultinomialNB 离散型朴素贝叶斯from sklearn.naive_bayes import MultinomialNB#LogisticRegression 逻辑回归from sklearn.linear_model import LogisticRegression#DecisionTreeClassifier 决策树from sklearn.tree import DecisionTreeClassifier#SVC 支持向量分类from sklearn.svm import SVC
关于交叉验证,之前有学习过:
K折交叉验证可以充分利用少样本的信息。K折交叉验证是将样本分成K个子样本集,拿出其中的K-1个子样本集来训练模型,用剩下的1个子样本集来对模型进行验证;再拿出K-1个训练模型,留下另外1个(与上一步的不同)子样本集进行验证......,如此交叉验证K次,每个子样本集验证1次,平均K次的结果作为一个模型的预测效果。
具体可见这里:留一交叉验证及SAS代码
交叉验证可充分利用样本的信息,在我们调参的时候,如果有多个模型供选择,或者一个模型需要选择一个最好的参数时,我们可以对每个模型进行一轮交叉验证,看那个模型或参数的效果最好。
但是有一个问题,那么多模型,每个模型都要试不同的参数甚至参数组合,这样成本是不是太高了?用For循环去试,又不够灵活,层次太分明。网格搜索解决这个问题的一个利器。Sklearn 的 GridSearchCV 就有一个现成的子模块可以用。它其实就是代替了人工暴力穷举,并且把很多功能包在了一起,让我们在调参时很方便。子模块的调用如下:
from sklearn.model_selection import GridSearchCV
GridSearchCV 的参数,常用的如下:
GridSearchCV(estimator, param_grid, scoring, cv)
- estimator 是分类器,如 DecisionTreeClassifier();
- parameter 是一个字典,它用来限定参数范围,一般取值是 {’参数名‘: 参数范围},比如决策树的参数一般是max_depth,其范围我们可以限定为 param_grid= {'max_depth': xrange(1, 10)},SVC 的参数有核函数(kernel),C 和 gamma,我们可以限定为:
- param_grid= {'kernel':('linear', 'rbf'), 'C':[1, 2, 4], 'gamma':[0.125, 0.25, 0.5 ,1, 2, 4]};
- cv:交叉验证参数,指定K折验证,默认是3;
- scoring 是模型的评价准则,如 roc_auc/recall/precision 等,可以缺失,默认使用 estimator 的误差估计函数,可选如下(来源官网):
关于 GribSearchCV 更详细的说明也可以看官网:
https://scikit-learn.org/0.17/modules/generated/sklearn.grid_search.GridSearchCV.html
需要注意的是,GribSearchCV 适合数据量比较小的场景,一旦数据量较大,就特别耗费计算资源和时间,此时还是得结合建模经验进行半手动调参,比如,可以先对一个影响最大得参数进行调参,得到最优后再调下一个参数,直到所有参数调节完,但这样得到得是一个局部最优而不是全局最优。
以 DecisionTreeClassifier 为例,我们可以这样使用网格搜索:
from sklearn.model_selection import GridSearchCVclf_DT=DecisionTreeClassifier()param_grid_DT= {'max_depth': [1,2,3,4,5,6]}grid=GridSearchCV(clf_DT, param_grid_DT, scoring='roc_auc', cv=5)grid.fit(X_train, y_train)
然而,得到的结果是:
注意,有人会认为是 DecisionTreeClassifier 只能解决二分类的问题,并不是。当数据是多分类时,就算是 sklearn 的二分类器,也将多分类的转换处理考虑了进来,处理方法通常是 'ovr',即one-vs-rest,顾名思义,就是某一类相对于其他类的可能,将多分类做多次2分类,来实现多分类的问题。
比如 LogisticRegression(),有一个默认的参数 multiclass=’ovr' 参数,SVC() 也有一个默认的参数 decision_function_shape='ovr',当数据是多分类时,都会自动用ovr算法进行处理。
这里报错是因为scoring='roc_auc',这个评价方法只适用于二分类,我们索性换成 accuracy:
from sklearn.model_selection import GridSearchCVclf_DT=DecisionTreeClassifier()param_grid_DT= {'max_depth': [1,2,3,4,5,6]}grid=GridSearchCV(clf_DT, param_grid_DT, scoring='accuracy', cv=5)grid.fit(X_train, y_train)print (grid.best_score_)print (grid.best_params_)
用 best_score_ 查看最高的得分,用 best_params_ 查看最优的参数,print 结果是:
0.9523809523809523{'max_depth': 5}
现在对这4个模型,我们都搜索一遍参数:
from sklearn.model_selection import GridSearchCVclf_DT=DecisionTreeClassifier()param_grid_DT= {'max_depth': [1,2,3,4,5,6]}clf_MNB=MultinomialNB()param_grid_MNB= {'alpha': [0.01,0.05,0.1,0.25,0.5,0.7,1]}clf_Logit=LogisticRegression()param_grid_logit= {'solver': ['liblinear','lbfgs','newton-cg','sag']}clf_svc=SVC()param_grid_svc={'kernel':('linear', 'rbf'), 'C':[1, 2, 4], 'gamma':[0.125, 0.25, 0.5 ,1, 2, 4]}clf=[clf_DT,clf_MNB,clf_Logit,clf_svc]param_grid=[param_grid_DT,param_grid_MNB,param_grid_logit,param_grid_svc]for i in range(0,4): grid=GridSearchCV(clf[i], param_grid[i], scoring='accuracy', cv=5) grid.fit(X_train, y_train) print (grid.best_params_,': ',grid.best_score_)
输出结果是:
{'max_depth': 4} : 0.9523809523809523{'alpha': 0.01} : 0.7047619047619048{'solver': 'sag'} : 0.9619047619047619{'C': 2, 'kernel': 'linear', 'gamma': 0.125} : 0.9809523809523809
所以 accuracy 最高的是 SVC,0.98,参数是
{'C': 2, 'kernel': 'linear', 'gamma': 0.125},
我们最终选择的模型:SVC(C=2, kernel='linear', gamma=0.125)
5. 模型测试和评价
我们在训练和调参时,用的是交叉验证,即只用了部分训练数据来训练,确定了最佳模型和参数之后,我们要用所有的训练样本再训练一遍作为预测模型,因为样本不能浪费。
clf=SVC(C=2, kernel='linear', gamma=0.125)clf.fit(X_train, y_train)clf.predict(X_test)
clf.predict(X_test),是fit后的模型在 X_test 上进行预测。预测完之后,可以用个 sklearn 的 metric 模块进行模型的评价,比如计算准确率、精准率和召回率:
from sklearn import metricsy_pred = clf.predict(X_test)#accuracyaccuracy=metrics.accuracy_score(y_true=y_test, y_pred=y_pred)print ('accuracy:',accuracy)#precisionprecision=metrics.precision_score(y_true=y_test, y_pred=y_pred,average="micro")print ('precision:',precision)#recallrecall=metrics.recall_score(y_true=y_test, y_pred=y_pred,average="micro")print ('recall:',recall)#实际值和预测值print (y_test)print (y_pred)
注意这里是多分类数据,因此计算精准和找回的时候需要加参数 average="micro"。结果如下:
accuracy: 0.9777777777777777precision: 0.9777777777777777recall: 0.9777777777777777y_test:[2 1 0 2 0 2 0 1 1 1 2 1 1 1 1 0 1 1 0 0 2 1 0 0 2 0 0 1 1 0 2 1 0 2 2 1 0 1 1 1 2 0 2 0 0]y_pred:[2 1 0 2 0 2 0 1 1 1 2 1 1 1 1 0 1 1 0 0 2 1 0 0 2 0 0 1 1 0 2 1 0 2 2 1 0 2 1 1 2 0 2 0 0]
我们再用之前其他三个模型的最优参数预测一下,看表现有什么不同,三个模型分别是:
clf_MNB=MultinomialNB(alpha=0.01)clf_DT=DecisionTreeClassifier(max_depth=4)clf_logit=LogisticRegression(solver='sag')
具体 code 略去,直接看结果:
clf_MNB:
accuracy: 0.6
precision: 0.6
recall: 0.6
clf_DT:
accuracy: 0.9777777777777777
precision: 0.9777777777777777
recall: 0.9777777777777777
clf_logit:
accuracy: 0.9333333333333333
precision: 0.9333333333333333
recall: 0.9333333333333333
可以看出 SVC 确实是几个模型中表现最好的。
6. 模型保存和调用
模型的保存和调用,使用 sklearn 的 joblib 子模块:
from sklearn.externals import joblib#模型保存到本地joblib.dump(clf,'SVC_model.m')#模型的恢复clf_tmp=joblib.load('SVC_model.m')
三、sklearn 建模流程总结
现在来总结一下 sklearn 建模的大致流程以及相关知识点:
1. 数据导入
- sklearn 自带数据集:sklearn.datasets
- 外部数据导入:pd.read_csv()
2. 数据处理
(1)划分训练集和测试集
- model_selection.train_test_split()
(2)数据清洗
- 缺失值填充:preprocessing.Imputer()
- 数据标准化:preprocessing.scale()
3. 特征工程
- 根据P值选:feature_selection.SelectFpr()
- 选出K个最高分特征:feature_selection.SelectKBest()
4. 模型调参/选择
- 交叉验证+网格搜索:model_selection.GridSearchCV()
5. 模型测试和评价
- 模型预测:model.predict()
- Accuracy:metrics.accuracy_score()
- Presicion:metrics.precision_score()
- Recall:metrics.recall_score()
6. 模型保存和调用
- 模型保存:joblib.dump()
- 模型调用:joblib.load()
以上就是 sklearn 建模的一个大体流程,无论是特征工程还是数据处理、建模,无论是有监督模型还是无监督学习,Sklearn 都封装了成熟的模块供我们调用。