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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


什么是设计模式一套被反复使用、多数人知晓的、经过分类编目的、代码 设计经验 的总结;使用设计模式是为了 可重用 代码、让代码 更容易 被他人理解、保证代码 可靠性;设计模式使代码编制  真正工程化;设计模式使软件工程的 基石脉络, 如同大厦的结构一样;并不直接用来完成代码的编写,而是 描述 在各种不同情况下,要怎么解决问题的一种方案;能使不稳定依赖于相对稳定、具体依赖于相对抽象,避免引
单一职责原则定义(Single Responsibility Principle,SRP)一个对象应该只包含 单一的职责,并且该职责被完整地封装在一个类中。Every  Object should have  a single responsibility, and that responsibility should be entirely encapsulated by t
动态代理和CGLib代理分不清吗,看看这篇文章,写的非常好,强烈推荐。原文截图*************************************************************************************************************************原文文本************
适配器模式将一个类的接口转换成客户期望的另一个接口,使得原本接口不兼容的类可以相互合作。
策略模式定义了一系列算法族,并封装在类中,它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
设计模式讲的是如何编写可扩展、可维护、可读的高质量代码,它是针对软件开发中经常遇到的一些设计问题,总结出来的一套通用的解决方案。
模板方法模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中,使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
迭代器模式提供了一种方法,用于遍历集合对象中的元素,而又不暴露其内部的细节。
外观模式又叫门面模式,它提供了一个统一的(高层)接口,用来访问子系统中的一群接口,使得子系统更容易使用。
单例模式(Singleton Design Pattern)保证一个类只能有一个实例,并提供一个全局访问点。
组合模式可以将对象组合成树形结构来表示“整体-部分”的层次结构,使得客户可以用一致的方式处理个别对象和对象组合。
装饰者模式能够更灵活的,动态的给对象添加其它功能,而不需要修改任何现有的底层代码。
观察者模式(Observer Design Pattern)定义了对象之间的一对多依赖,当对象状态改变的时候,所有依赖者都会自动收到通知。
代理模式为对象提供一个代理,来控制对该对象的访问。代理模式在不改变原始类代码的情况下,通过引入代理类来给原始类附加功能。
工厂模式(Factory Design Pattern)可细分为三种,分别是简单工厂,工厂方法和抽象工厂,它们都是为了更好的创建对象。
状态模式允许对象在内部状态改变时,改变它的行为,对象看起来好像改变了它的类。
命令模式将请求封装为对象,能够支持请求的排队执行、记录日志、撤销等功能。
备忘录模式(Memento Pattern)保存一个对象的某个状态,以便在适当的时候恢复对象。备忘录模式属于行为型模式。 基本介绍 **意图:**在不破坏封装性的前提下,捕获一个对象的内部状态,并在该
顾名思义,责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为
享元模式(Flyweight Pattern)(轻量级)(共享元素)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结