一把 sklearn 走天下 | 统计师的Python日记 第12天

本文是【统计师的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日记【第12天:一把 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 datasets
from sklearn.feature_selection import SelectKBest
from 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_split
X=iris.data
y=iris.target
X_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 Imputer
impt= Imputer(missing_values='NaN', strategy='mean', axis=0)
#还可以用"median"、"most_frequent"等来填充          
impt.fit(X)         
impt.transform(X) 
  • 数据标准化(有时候特征的量纲不一致,或者存在很多异常值,需要进行标准化处理)
from sklearn import preprocessing
X_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(<func>, alpha)

<func>是筛选的统计方法,默认是方差检验的F检验对应p值,此外还可以选chi2(卡方检验)

  • f_regression(回归的F检验P值)
  • mutal_info_regression(利用特征和标签之间的互信息)
  • 等等,具体可查阅官网
from sklearn.feature_selection import SelectFpr
selectFea=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 GridSearchCV

clf_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 GridSearchCV

clf_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 GridSearchCV

clf_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 metrics

y_pred = clf.predict(X_test)

#accuracy
accuracy=metrics.accuracy_score(y_true=y_test, y_pred=y_pred)
print ('accuracy:',accuracy)

#precision
precision=metrics.precision_score(y_true=y_test, y_pred=y_pred,average="micro")
print ('precision:',precision)

#recall
recall=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.9777777777777777
precision: 0.9777777777777777
recall: 0.9777777777777777
y_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 都封装了成熟的模块供我们调用。

但是,如果数据换成其他一种形式,比如文本数据,我们应该怎么怎么处理?其实仅仅是多了一个文本向量化的过程,回复 sktext 看一个文本建模的例子。

下期预告:tensorflow

原文发布于微信公众号 - 数说工作室(shushuojun)

原文发表时间:2019-02-11

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券