使用sklearn进行数据挖掘

标签: tuicool | 发表时间:2016-10-16 08:00 | 作者:
出处:http://itindex.net/admin/pagedetail

1 使用sklearn进行数据挖掘

1.1 数据挖掘的步骤

数据挖掘通常包括数据采集,数据分析,特征工程,训练模型,模型评估等步骤。使用sklearn工具可以方便地进行特征工程和模型训练工作,在 《使用sklearn做单机特征工程》中,我们最后留下了一些疑问:特征处理类都有三个方法fit、transform和fit_transform,fit方法居然和模型训练方法fit同名(不光同名,参数列表都一样),这难道都是巧合?

显然,这不是巧合,这正是sklearn的设计风格。我们能够更加优雅地使用sklearn进行特征工程和模型训练工作。此时,不妨从一个基本的数据挖掘场景入手:

我们使用sklearn进行虚线框内的工作(sklearn也可以进行文本特征提取)。通过分析sklearn源码,我们可以看到除训练,预测和评估以外,处理其他工作的类都实现了3个方法:fit、transform和fit_transform。从命名中可以看到,fit_transform方法是先调用fit然后调用transform,我们只需要关注fit方法和transform方法即可。

transform方法主要用来对特征进行转换。从可利用信息的角度来说,转换分为无信息转换和有信息转换。无信息转换是指不利用任何其他信息进行转换,比如指数、对数函数转换等。有信息转换从是否利用目标值向量又可分为无监督转换和有监督转换。无监督转换指只利用特征的统计信息的转换,统计信息包括均值、标准差、边界等等,比如标准化、PCA法降维等。有监督转换指既利用了特征信息又利用了目标值信息的转换,比如通过模型选择特征、LDA法降维等。通过总结常用的转换类,我们得到下表:

参数列表 类别 fit方法有用 说明
sklearn.preprocessing StandardScaler 特征 无监督 Y 标准化
sklearn.preprocessing MinMaxScaler 特征 无监督 Y 区间缩放
sklearn.preprocessing Normalizer 特征 无信息 N 归一化
sklearn.preprocessing Binarizer 特征 无信息 N 定量特征二值化
sklearn.preprocessing OneHotEncoder 特征 无监督 Y 定性特征编码
sklearn.preprocessing Imputer 特征 无监督 Y 缺失值计算
sklearn.preprocessing PolynomialFeatures 特征 无信息 N 多项式变换(fit方法仅仅生成了多项式的表达式)
sklearn.preprocessing FunctionTransformer 特征 无信息 N 自定义函数变换(自定义函数在transform方法中调用)
sklearn.feature_selection VarianceThreshold 特征 无监督 Y 方差选择法
sklearn.feature_selection SelectKBest 特征/特征+目标值 无监督/有监督 Y 自定义特征评分选择法
sklearn.feature_selection SelectKBest+chi2 特征+目标值 有监督 Y 卡方检验选择法
sklearn.feature_selection RFE 特征+目标值 有监督 Y 递归特征消除法
sklearn.feature_selection SelectFromModel 特征+目标值 有监督 Y 自定义模型训练选择法
sklearn.decomposition PCA 特征 无监督 Y PCA降维
sklearn.lda LDA 特征+目标值 有监督 Y LDA降维

不难看到,只有有信息的转换类的fit方法才实际有用,显然fit方法的主要工作是获取特征信息和目标值信息,在这点上,fit方法和模型训练时的fit方法就能够联系在一起了:都是通过分析特征和目标值,提取有价值的信息,对于转换类来说是某些统计量,对于模型来说可能是特征的权值系数等。另外,只有有监督的转换类的fit和transform方法才需要特征和目标值两个参数。fit方法无用不代表其没实现,而是除合法性校验以外,其并没有对特征和目标值进行任何处理,Normalizer的fit方法实现如下:

1 def fit(self, X, y=None):
2         """Do nothing and return the estimator unchanged
3         This method is just there to implement the usual API and hence
4         work in pipelines.
5         """
6         X = check_array(X, accept_sparse='csr')
7         return self

基于这些特征处理工作都有共同的方法,那么试想可不可以将他们组合在一起?在本文假设的场景中,我们可以看到这些工作的组合形式有两种:流水线式和并行式。基于流水线组合的工作需要依次进行,前一个工作的输出是后一个工作的输入;基于并行式的工作可以同时进行,其使用同样的输入,所有工作完成后将各自的输出合并之后输出。sklearn提供了包pipeline来完成流水线式和并行式的工作。

1.2 数据初貌

在此,我们仍然使用IRIS数据集来进行说明。为了适应提出的场景,对原数据集需要稍微加工:

1 from numpy import hstack, vstack, array, median, nan
 2 from numpy.random import choice
 3 from sklearn.datasets import load_iris
 4 
 5 #特征矩阵加工
 6 #使用vstack增加一行含缺失值的样本(nan, nan, nan, nan)
 7 #使用hstack增加一列表示花的颜色(0-白、1-黄、2-红),花的颜色是随机的,意味着颜色并不影响花的分类
 8 iris.data = hstack((choice([0, 1, 2], size=iris.data.shape[0] 1).reshape(-1,1), vstack((iris.data, array([nan, nan, nan, nan]).reshape(1,-1)))))
 9 #目标值向量加工
10 #增加一个目标值,对应含缺失值的样本,值为众数
11 iris.target = hstack((iris.target, array([median(iris.target)])))

1.3 关键技术

并行处理,流水线处理,自动化调参,持久化是使用sklearn优雅地进行数据挖掘的核心。并行处理和流水线处理将多个特征处理工作,甚至包括模型训练工作组合成一个工作(从代码的角度来说,即将多个对象组合成了一个对象)。在组合的前提下,自动化调参技术帮我们省去了人工调参的反锁。训练好的模型是贮存在内存中的数据,持久化能够将这些数据保存在文件系统中,之后使用时无需再进行训练,直接从文件系统中加载即可。

2 并行处理

并行处理使得多个特征处理工作能够并行地进行。根据对特征矩阵的读取方式不同,可分为整体并行处理和部分并行处理。整体并行处理,即并行处理的每个工作的输入都是特征矩阵的整体;部分并行处理,即可定义每个工作需要输入的特征矩阵的列。

2.1 整体并行处理

pipeline包提供了FeatureUnion类来进行整体并行处理:

1 from numpy import log1p
 2 from sklearn.preprocessing import FunctionTransformer
 3 from sklearn.preprocessing import Binarizer
 4 from sklearn.pipeline import FeatureUnion
 5 
 6 #新建将整体特征矩阵进行对数函数转换的对象
 7 step2_1 = ('ToLog', FunctionTransformer(log1p))
 8 #新建将整体特征矩阵进行二值化类的对象
 9 step2_2 = ('ToBinary', Binarizer())
10 #新建整体并行处理对象
11 #该对象也有fit和transform方法,fit和transform方法均是并行地调用需要并行处理的对象的fit和transform方法
12 #参数transformer_list为需要并行处理的对象列表,该列表为二元组列表,第一元为对象的名称,第二元为对象
13 step2 = ('FeatureUnion', FeatureUnion(transformer_list=[step2_1, step2_2, step2_3]))

2.2 部分并行处理

整体并行处理有其缺陷,在一些场景下,我们只需要对特征矩阵的某些列进行转换,而不是所有列。pipeline并没有提供相应的类(仅OneHotEncoder类实现了该功能),需要我们在FeatureUnion的基础上进行优化:

fromsklearn.pipelineimportFeatureUnion,_fit_one_transformer,_fit_transform_one,_transform_onefromsklearn.externals.joblibimportParallel,delayedfromscipyimportsparseimportnumpyasnp#部分并行处理,继承FeatureUnionclassFeatureUnionExt(FeatureUnion):#相比FeatureUnion,多了idx_list参数,其表示每个并行工作需要读取的特征矩阵的列def__init__(self,transformer_list,idx_list,n_jobs=1,transformer_weights=None):self.idx_list=idx_list
        FeatureUnion.__init__(self,transformer_list=map(lambdatrans:(trans[0],trans[1]),transformer_list),n_jobs=n_jobs,transformer_weights=transformer_weights)#由于只部分读取特征矩阵,方法fit需要重构deffit(self,X,y=None):
        transformer_idx_list=map(lambdatrans,idx:(trans[0],trans[1],idx),self.transformer_list,self.idx_list)transformers=Parallel(n_jobs=self.n_jobs)(#从特征矩阵中提取部分输入fit方法delayed(_fit_one_transformer)(trans,X[:,idx],y)forname,trans,idxintransformer_idx_list)self._update_transformer_list(transformers)returnself#由于只部分读取特征矩阵,方法fit_transform需要重构deffit_transform(self,X,y=None,**fit_params):
        transformer_idx_list=map(lambdatrans,idx:(trans[0],trans[1],idx),self.transformer_list,self.idx_list)result=Parallel(n_jobs=self.n_jobs)(#从特征矩阵中提取部分输入fit_transform方法delayed(_fit_transform_one)(trans,name,X[:,idx],y,self.transformer_weights,**fit_params)forname,trans,idxintransformer_idx_list)Xs,transformers=zip(*result)self._update_transformer_list(transformers)ifany(sparse.issparse(f)forfinXs):
            Xs=sparse.hstack(Xs).tocsr()else:
            Xs=np.hstack(Xs)returnXs#由于只部分读取特征矩阵,方法transform需要重构deftransform(self,X):
        transformer_idx_list=map(lambdatrans,idx:(trans[0],trans[1],idx),self.transformer_list,self.idx_list)Xs=Parallel(n_jobs=self.n_jobs)(#从特征矩阵中提取部分输入transform方法delayed(_transform_one)(trans,name,X[:,idx],self.transformer_weights)forname,trans,idxintransformer_idx_list)ifany(sparse.issparse(f)forfinXs):
            Xs=sparse.hstack(Xs).tocsr()else:
            Xs=np.hstack(Xs)returnXs

在本文提出的场景中,我们对特征矩阵的第1列(花的颜色)进行定性特征编码,对第2、3、4列进行对数函数转换,对第5列进行定量特征二值化处理。使用FeatureUnionExt类进行部分并行处理的代码如下:

1 from numpy import log1p
 2 from sklearn.preprocessing import OneHotEncoder
 3 from sklearn.preprocessing import FunctionTransformer
 4 from sklearn.preprocessing import Binarizer
 5 
 6 #新建将部分特征矩阵进行定性特征编码的对象
 7 step2_1 = ('OneHotEncoder', OneHotEncoder(sparse=False))
 8 #新建将部分特征矩阵进行对数函数转换的对象
 9 step2_2 = ('ToLog', FunctionTransformer(log1p))
10 #新建将部分特征矩阵进行二值化类的对象
11 step2_3 = ('ToBinary', Binarizer())
12 #新建部分并行处理对象
13 #参数transformer_list为需要并行处理的对象列表,该列表为二元组列表,第一元为对象的名称,第二元为对象
14 #参数idx_list为相应的需要读取的特征矩阵的列
15 step2 = ('FeatureUnionExt', FeatureUnionExt(transformer_list=[step2_1, step2_2, step2_3], idx_list=[[0], [1, 2, 3], [4]]))

3 流水线处理

pipeline包提供了Pipeline类来进行流水线处理。流水线上除最后一个工作以外,其他都要执行fit_transform方法,且上一个工作输出作为下一个工作的输入。最后一个工作必须实现fit方法,输入为上一个工作的输出;但是不限定一定有transform方法,因为流水线的最后一个工作可能是训练!

根据本文提出的场景,结合并行处理,构建完整的流水线的代码如下:

1 from numpy import log1p
 2 from sklearn.preprocessing import Imputer
 3 from sklearn.preprocessing import OneHotEncoder
 4 from sklearn.preprocessing import FunctionTransformer
 5 from sklearn.preprocessing import Binarizer
 6 from sklearn.preprocessing import MinMaxScaler
 7 from sklearn.feature_selection import SelectKBest
 8 from sklearn.feature_selection import chi2
 9 from sklearn.decomposition import PCA
10 from sklearn.linear_model import LogisticRegression
11 from sklearn.pipeline import Pipeline
12 
13 #新建计算缺失值的对象
14 step1 = ('Imputer', Imputer())
15 #新建将部分特征矩阵进行定性特征编码的对象
16 step2_1 = ('OneHotEncoder', OneHotEncoder(sparse=False))
17 #新建将部分特征矩阵进行对数函数转换的对象
18 step2_2 = ('ToLog', FunctionTransformer(log1p))
19 #新建将部分特征矩阵进行二值化类的对象
20 step2_3 = ('ToBinary', Binarizer())
21 #新建部分并行处理对象,返回值为每个并行工作的输出的合并
22 step2 = ('FeatureUnionExt', FeatureUnionExt(transformer_list=[step2_1, step2_2, step2_3], idx_list=[[0], [1, 2, 3], [4]]))
23 #新建无量纲化对象
24 step3 = ('MinMaxScaler', MinMaxScaler())
25 #新建卡方校验选择特征的对象
26 step4 = ('SelectKBest', SelectKBest(chi2, k=3))
27 #新建PCA降维的对象
28 step5 = ('PCA', PCA(n_components=2))
29 #新建逻辑回归的对象,其为待训练的模型作为流水线的最后一步
30 step6 = ('LogisticRegression', LogisticRegression(penalty='l2'))
31 #新建流水线处理对象
32 #参数steps为需要流水线处理的对象列表,该列表为二元组列表,第一元为对象的名称,第二元为对象
33 pipeline = Pipeline(steps=[step1, step2, step3, step4, step5, step6])

4 自动化调参

网格搜索为自动化调参的常见技术之一,grid_search包提供了自动化调参的工具,包括GridSearchCV类。对组合好的对象进行训练以及调参的代码如下:

1 from sklearn.grid_search import GridSearchCV
2 
3 #新建网格搜索对象
4 #第一参数为待训练的模型
5  #param_grid为待调参数组成的网格,字典格式,键为参数名称(格式“对象名称__子对象名称__参数名称”),值为可取的参数值列表
6  grid_search = GridSearchCV(pipeline, param_grid={'FeatureUnionExt__ToBinary__threshold':[1.0, 2.0, 3.0, 4.0], 'LogisticRegression__C':[0.1, 0.2, 0.4, 0.8]})
7 #训练以及调参
8 grid_search.fit(iris.data, iris.target)

5 持久化

externals.joblib包提供了dump和load方法来持久化和加载内存数据:

1 #持久化数据
2 #第一个参数为内存中的对象
3 #第二个参数为保存在文件系统中的名称
4 #第三个参数为压缩级别,0为不压缩,3为合适的压缩级别
5 dump(grid_search, 'grid_search.dmp', compress=3)
6 #从文件系统中加载数据到内存中
7 grid_search = load('grid_search.dmp')

6 回顾

类或方法 说明
sklearn.pipeline Pipeline 流水线处理
sklearn.pipeline FeatureUnion 并行处理
sklearn.grid_search GridSearchCV 网格搜索调参
externals.joblib dump 数据持久化
externals.joblib load 从文件系统中加载数据至内存

注意:组合和持久化都会涉及pickle技术, 在sklearn的技术文档中有说明,将lambda定义的函数作为FunctionTransformer的自定义转换函数将不能pickle化。

7 总结

2015年我设计了一个 基于sklearn的自动化特征工程的工具,其以Mysql数据库作为原始数据源,提供了“灵活的”特征提取、特征处理的配置方法,同时重新封装了数据、特征和模型,以方便调度系统识别。说灵活,其实也只是通过配置文件的方式定义每个特征的提取和处理的sql语句。但是纯粹使用sql语句来进行特征处理是很勉强的,除去特征提取以外,我又造了一回轮子,原来sklearn提供了这么优秀的特征处理、工作组合等功能。所以,我在这个博客中先不提任何算法和模型,先从数据挖掘工作的第一步开始,使用基于Python的各个工具把大部分步骤都走了一遍(抱歉,我暂时忽略了特征提取),希望这样的梳理能够少让初学者走弯路吧。

8 参考资料

  1. 使用sklearn做单机特征工程
  2. FunctionTransformer
  3. Github:jasonfreak/ali2015

相关 [sklearn 数据挖掘] 推荐:

使用sklearn进行数据挖掘

- - IT瘾-tuicool
1 使用sklearn进行数据挖掘. 数据挖掘通常包括数据采集,数据分析,特征工程,训练模型,模型评估等步骤. 使用sklearn工具可以方便地进行特征工程和模型训练工作,在 《使用sklearn做单机特征工程》中,我们最后留下了一些疑问:特征处理类都有三个方法fit、transform和fit_transform,fit方法居然和模型训练方法fit同名(不光同名,参数列表都一样),这难道都是巧合.

数据挖掘是神马?

- - 互联网分析
1、数据挖掘需要‘神马样’的流程.  2、哥,有没有详细点的,来个给力的. 4、数据在统计意义上有哪些类型. 9、知道这些工具不知道如何在工作中用呀. 11、还有没有更人性化、智能化的展现. 12、上面这图看起来很给力,背后很复杂吧.  16、转载的留个来源 ,毕竟是我辛苦收集和想出来的,谢谢. 忘记“大数据”,从“中数据”开始.

这就是数据挖掘

- - 互联网分析
当今数据库的容量已经达到上万亿的水平(T)— 1,000,000,000,000个字节. 在这些大量数据的背后隐藏了很多具有决策意义的信息,那么怎么得到这些“知识”呢. 也就是怎样通过一颗颗的树木了解到整个森林的情况. 计 算机科学对这个问题给出的最新回答就是:数据挖掘,在“数据矿山”中找到蕴藏的“知识金块”,帮助企业减少不必要投资的同时提高资金回报.

关于数据挖掘

- - 牛国柱
以下内容来自网络,关于数据挖掘的一些最基本的知识. 数据挖掘是对一系列数据进行分析和挖掘的方法的统称,在精准营销领域,最常用的数据挖掘方法主要包括以下三类:分类、聚类、关联. 分类(Classify)属于预测性模型. 分类模型的构建需要“训练样本”,训练样本中的每一个个体的类别必须是明确的. 分类模型的特征变量一般称为“自变量”,又叫“预测变量”,类别变量称为“目标变量”.

数据挖掘与Taco Bell编程

- everfly - 译言-每日精品译文推荐
来源Data Mining and Taco Bell Programming. Programmer Ted Dziuba suggests an alternative to traditional program that he called "Taco Bell Programming." The Taco Bell chain creates multiple menu items from about eight different ingredients.

使用Weka进行数据挖掘

- - 搜索研发部官方博客
数据挖掘、机器学习这些字眼,在一些人看来,是门槛很高的东西. 诚然,如果做算法实现甚至算法优化,确实需要很多背景知识. 但事实是,绝大多数数据挖掘工程师,不需要去做算法层面的东西. 他们的精力,集中在特征提取,算法选择和参数调优上. 那么,一个可以方便地提供这些功能的工具,便是十分必要的了. 而weka,便是数据挖掘工具中的佼佼者.

数据挖掘 - 分类算法比较

- - IBM developerWorks 中国 : 文档库
随着计算能力、存储、网络的高速发展,人类积累的数据量正以指数速度增长. 对于这些数据,人们迫切希望从中提取出隐藏其中的有用信息,更需要发现更深层次的规律,对决策,商务应用提供更有效的支持. 为了满足这种需求,数据挖掘技术的得到了长足的发展,而分类在数据挖掘中是一项非常重要的任务,目前在商业上应用最多.

数据挖掘分类技术

- - CSDN博客云计算推荐文章
从分类问题的提出至今,已经衍生出了很多具体的分类技术. 下面主要简单介绍四种最常用的分类技术,不过因为原理和具体的算法实现及优化不是本书的重点,所以我们尽量用应用人员能够理解的语言来表述这些技术. 而且我们会在第4章再次给读者讲述分类算法和相关原理. 在我们学习这些算法之前必须要清楚一点,分类算法不会百分百准确.

数据挖掘之R与SQL

- Wolf - 刘思喆 @ 贝吉塔行星
今天看到老同学@JulieJulieJulieJulie 的浪漫求婚,真的很浪漫、很唯美、很感动. 正如评论说的,我们又相信爱情了. 于是,小兴奋,睡不着,爬起来补一篇文章. 最近在数据挖掘专业网站 KDnuggets 上刊出了2011年度关于数据挖掘/分析语言流行度的调查,不出意料R、SQL、Python果然排在了前三位.

数据挖掘的标准流程

- - CSDN博客推荐文章
    CRISP-DM (cross-industry standard process for data mining), 即为"跨行业数据挖掘过程标准". 此KDD过程模型于1999年欧盟机构联合起草. 通过近几年的发展,CRISP-DM 模型在各种KDD过程模型中占据领先位置,采用量达到近60%.(数据引自Cios and Kurgan于2005年合著的论文trands in data mining and knowledge discovery中 )    在1996年,当时数据挖掘市场是年轻而不成熟的,但是这个市场显示了爆炸式的增长.