Sklearn学习之路2——围绕评估器转换器展开讨论

1. 写在前面

在上一讲中,我们对于Sklearn框架有了一个较为直观的认识,但是对于其中的细节部分,可能还是不知甚解。这次,我们将会详细的介绍其中的一些知识,包括:Sklearn版本注意事项、最基本的评估器与转换器、fit、transform与fit_transform的区别、pipeline使用,tfidf与CountVectorizer方法等。

2. Sklearn版本注意事项

在网上很多Sklearn的例子,但是很多时候copy下来又运行不了,其实很多时候是因为Sklearn版本不同。机器学习是一个非常活跃的领域,而Sklearn又是一个非常活跃的框架,版本更新迭代速度很快,而且修改比较多,很多时候上一个版本的函数方法,在下一个版本中就已经不能使用了。大家需要自己去Sklearn官网里查看最新的API。另外一点,好在Pycharm里会提醒,在接下来的版本中可能移除的方法,让你及时调整代码。因此如果出现了网上的示例不能运行的情况,有可能是版本已经更新了。

3. 评估器与转换器

说到评估器与转换器,大家可能没有一个直观的认识。事实上,基本上大部分的分类器都属于评估器,这点你可以从分类器的包名可以看到:

这里面类汇总,第一个为基础评估器,第二个为基础分类器,最后一个为基础转换器。基本上所有的评估器与转换器都有三个基本方法,fit,transform,fit_transform。为什么着重讲这个,因为在pipeline中,它的最后一部分为评估器,也就是说最后一步一定是个分类器,而前面的预处理、降维、正则化等都是转换器。这点我们会在后面讲到。

4. fit、transform与fit_transform的区别

其实程序员最应去的一个地方就是Stackoverflow,那里有最权威、最清楚的Bug调试解决方案。虽然大部分都是英语,但是英语解释的比较确切。

fit原义指的是安装、使适合的意思,其实有点train的含义但是和train不同的是,它并不是一个训练的过程,而是一个适配的过程,过程都是定死的,最后只是得到了一个统一的转换的规则模型。

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

而fit_transform方法则是把上述2个过程统一起来,对模型先训练,然后根据输入的训练数据返回一个转换矩阵。这个过程通常只存在训练过程中。在Pipeline中尤为明显。

5. pipeline的使用

给出一幅图,就可以大致了解pipeline的运行方式与流程:

这里我们可以看到pipeline的最后一步一定是一个分类器,而开始部分可以是一个规约化,中间可以是降维、可以是特征选取等等一套流程。当然,这里用的都是包里自带的评估器与分类器,如果想自己写其中的一个过程然后添加到整个pipeline中,还需要继承基类(第3节讲到)后才能添加进去。
具体的使用样例如下:

from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn.linear_model import LogisticRegression

from sklearn.pipeline import Pipeline

pipe_lr = Pipeline([('sc',StandardScaler()),('pca',PCA(n_components=2)),('clf',LogisticRegression(random_state=1))
                    ])
pipe_lr.fit(X_train,y_train)
print('Test accuracy: %.3f' % pipe_lr.score(X_test,y_test))

                # Test accuracy: 0.947

6. CountVectorizer()与TfidfTransformer()

在第三节中,我们讲到了评估器与转换器,这2个都是有上面那3个方法,评估器可能还会多一个predict预测这个方法。主要是用来分类的。

同样的,评估器里的算法多为机器学习算法,而转换器里的算法多为转换算法。像TFIDF算法就是转换器,它只不过是把一个文档列表转换为一个TFIDF矩阵,但是如何转换是有一个模型的,这个模型这个被训练语料fit后的模型,它同样可以被用来转换(transform)测试语料,例如下面这代码

#初始化一个ftidf对象
tfidf=TfidfTransformer();
from sklearn.feature_extraction.text import CountVectorizer
#初始化一个统计词频对象
count_vect = CountVectorizer()
#返回的是一个稀疏矩阵
train_data = count_vect.fit_transform(train_data)
#通过稀疏矩阵获得tfidf矩阵
train_result=tfidf.fit_transform(train_data);
#使用同样的统计词频模型来生成训练语料的统计词频矩阵。
test_data = count_vect.transform(test_data)
#使用同样的模型对测试语料转换,可以得到和测试语料同样的TFIDF矩阵。
test_result=tfidf.transform(test_data);

这里我们在使用tfidf转换器的同时需要使用一个统计词频转换器,因为统计词频转换器可以把文章列表转换为一个词频的矩阵,如下表:

文档顺序 单词1 单词2 ···
1 1 2 ···
2 0 2 ···
··· ··· ··· ···

但是其实它真实存储的时候是以稀疏矩阵存储,也就是只存储非0的单元。这样做其实有2点好处。

  1. 节省空间,因为统计词频显然是一个稀疏的矩阵,词表为列数,而一个文档含有的单词数非常少。因此只存储非0的单元节省空间。
  2. 利于扩展,我们的词表使用的训练集训练的,而如果使用同一转换器来转换测试集的时候,即使原有词表中未包含测试集内的单词,也很容易扩展,只需要在稀疏矩阵后添加一个矩阵单元即可。例如:

(0,18375) 1
(0,19325) 1
(0,39321) 1
(0,45163) 1
(0,110448) 1
(0,22986) 1
(0,115259) 1
(0,31639) 1

上边是第一行的稀疏矩阵,最大的值为115259,也就是说最大的列假设为115259列,如果测试集中出现了一个单词,这个单词在前115259个词都没出现过,这时候,只需要:

(1,115260) 1

即可,非常容易扩展。

这时候,才能使用tfidf转换器,把这个转换成相应的tfidf值,因为只有这样做过了,tfidf转换器才能方便的转换。因为这时候,无论是一篇文章的词总数,还是文档总数,还是出现目标词的文档数都非常容易的统计出,这样对于TFIDF公式:

TFIDF=TFIDF

=×log+1

其实最后的+1不一定放上去,主要是为了防止查找原语料中不存在的词时,分母不为0。

使用tfidf转换器后,整个稀疏矩阵就成这样子了:

(0,31639) 0.350232605058
(0,115259) 0.287191449938
(0,22986) 0.325286181826
(0,110448) 0.38664944433
(0,45163) 0.399257482535
(0,39321) 0.308066927057
(0,19325) 0.350232605058
(0,18375) 0.403205473668

大家可以看到,与词频统计的稀疏矩阵的非0点坐标是一致的不同的就是其中的值。

7. 小结

我们这次对于sklearn有了一个更加明确的认识,在此基础上已经可以做一些特定的实验了。但是如何进行特征选择和最终的实验评估报告还并未说明,这几部分将在以后的文章中更新。

相关文章

迭代器模式(Iterator)迭代器模式(Iterator)[Cursor]意图...
高性能IO模型浅析服务器端编程经常需要构造高性能的IO模型,...
策略模式(Strategy)策略模式(Strategy)[Policy]意图:定...
访问者模式(Visitor)访问者模式(Visitor)意图:表示一个...
命令模式(Command)命令模式(Command)[Action/Transactio...
生成器模式(Builder)生成器模式(Builder)意图:将一个对...