第4章 特征提取

在前面的例子中,我们实际上使用了真实数据(线性回归)与样本距离(KNN)来作为机器学习时的特征,简言之,机器学习的核心是从各种特征中进行学习进而归纳规律。在本章接下来的部分,我们将学习如何从文本中提取特征以实现抽象化,从而完成机器学习任务。

知识结构

温馨提示:有关NLTK包和Google News语料库的下载与使用详见附录

4.1 从类别变量中提取特征

类别变量顾名思义,就是指在某一主题下进行取值的变量。常见的类别变量有性别(取值为男、女)、城市(取值为北京、上海、广州等)、学校、饭店等等。我们针对类别变量的特征提取遵循一条很简单的原则: 每一个取值都自成一个维度。例如对于城市,我们可以有如下假设:

v北京=(1,0,0)T,v上海=(0,1,0)T,v广州=(0,0,1)T.\begin{align*} v_{北京}=(1, 0, 0)^T,\\ v_{上海}=(0, 1, 0)^T,\\ v_{广州}=(0, 0, 1)^T. \end{align*} v北京=(1,0,0)T,v上海=(0,1,0)T,v广州=(0,0,1)T.

基本思想就是某一主题下不同分支之间是相互独立不相干的。如果某段文字按照上述规则被归纳出了(12, 3, 1),亦即12v北京+3v上海+v广州12v_{北京}+3v_{上海}+v_{广州}12v北京+3v上海+v广州, 那么我们就可以说这段文字的主题更接近于北京,其次是上海和广州。

在scikit-learn中使用如下代码以完成上述算法:

from sklearn.feature_extraction import DictVectorizer
onehot_encoder = DictVectorizer()
X = [{'city' : '北京'},{'city' : '上海'},{'city' : '广州'}
]
print(onehot_encoder.fit_transform(X).toarray())

要点

  1. 从sklearn.feature_extraction库中调用DictVector类并创建实例
  2. 声明类别变量,亦即字典
  3. 调用实例的fit_transform方法处理类别变量/字典,最后使用toarray方法返回结果

思考

我们再一次见到了fit_transform方法,上一次我们使用它还是在KNN算法优化的时候——我们通过StandardScaler类将我们的原始数据标准化缩放成一个均值为0方差为1的标准数据来提高模型的准确性。

不难发现: scikit learn中所有对数据处理的类都要经过这样一番操作——fit方法来归纳规则,transform对指定数据集施加规则,而fit_transform方法则会同时使用两种方法,一石二鸟!

批注

上述算法实际上被称作one-hot编码算法,原理已在上文中阐述。

那么接下来,让我们把特征提取和数据缩放技术综合在一起吧!

4.2 特征标准化

本节我们会额外介绍两种缩放器: scale函数与RobustScaler类

from sklearn import preprocessing
import numpy as np
X = np.array([[0., 0., 5., 13., 9., 1.],[0., 0, 13., 15., 10., 15.],[0., 3., 15., 2., 0., 11.]
])
print(preprocessing.scale(X))

注意,这里假定特征提取已经完成,上述代码中的X应当是我们特征提取的最终结果。

思考

注意到我们依旧从sklearn的preprocessing模块导入了scale函数。在上一章中我们也是从该库中导入StandardScaler类,所以至此我们应当建立一种条件反射,一旦需要用到缩放技术就应该想到prerocessing库,并且应当回忆起导入的路径:sklearn → scale / StandardScaler / RobustScaler

批注

RobustScaler 对于异常值具有更好的稳定性,它会自动减小异常值的影响。

4.3 从文本中提取特征

本节内容是全章的重头戏!笔者希望读者从头至尾应有如下“顶层设计”意识:起先我们会建立一个基本的词袋模型,它将会有一系列最基础的功能,然而这还不够,我们需要多种技术(停用词、词干提取与词形还原)来简化我们的数据(或者说剔除不必要的维度)以减小算法时间和空间复杂度,进一步优化模型,接着我们需要为不同单词和词组附加权重以提高模型精确度,最后在建立了一个几近完美的模型后, 我们会介绍一种成熟的词向量体系以作比较!

知识结构

4.3.1 词袋模型

词袋模型是最常用的文本表示法,该模型会忽略所有语法以及所有单词的顺序。其灵感来自于包含类似单词的文档通常有相似的含义或主题这一现象。该算法针对对象是文本文档,并且会为文档中每一个独特的单词创建单独的一个维度(回忆类别变量一节)。

# 创建语料库,包含两个文档
corpus = ['UNC played Duke in basketball','Duke lost the basketball game'
]from sklearn.feature_extraction.text import CountVectorizer
vectorizer = CountVectorizer()
print(vectorizer.fit_transform(corpus).todense())
print(vectorizer.vocabulary_)

要点

  1. 使用创建语料库
  2. 从sklearn.feature_extraction.text库下导入CountVectorizer类并创建实例
  3. 调用fit_transform方法处理语料库并使用todense方法返回结果
  4. 调用 vocabulary_ 属性返回生成的单词特征库(下划线一定不要省略!)

在建立最基本的词袋模型后,我们可以继续fit_transform其他文档,并根据得出的特征向量计算不同文档间的相似度(用向量间的距离表示)。

corpus.append('I ate a sandwich') # 添加新文档
print(vectorizer.fit_transform(corpus).todense()) # 再次fit_transform
print(vectorizer.vocabulary_)from sklearn.metrics.pairwise import euclidean_distances
X = vectorizer.fit_transform(corpus).todense()
print('1号文档和2号文档间的距离: ' , euclidean_distances(X[0], X[1]))
print('1号文档和3号文档间的距离: ' , euclidean_distances(X[0], X[2]))
print('2号文档和3号文档间的距离: ' , euclidean_distances(X[2], X[1]))

4.3.2 & 4.3.3 停用词过滤 & 词干提取和词形还原

NLTK安装详见附录1

我们看到在上述结果中出现了单词the,这对我们的特征提取没有任何帮助!而且会额外占用维度。我们称这类无助于特征提取并且会额外占用维度的单词为停用词。然而值得注意的是,不同语言的停用词是不同的,例如英语的a, an, the和中文的“了”“的”“是”。故我们需要在模型创建时特别指定语言:

vectorizer = CountVectorizer(stop_words='english')
print(vectorizer.fit_transform(corpus).todense())
print(vectorizer.vocabulary_)corpus = ['He ate the sandwiches','Every sandwich was eaten by him'
]
vectorizer = CountVectorizer(binary = True, stop_words='english')
print(vectorizer.fit_transform(corpus).todense())
print(vectorizer.vocabulary_)

要点

在创建CountVectorizer的实例时指定stop_words的语种。

接下来是词干提取与词形还原
由于英语属于屈折语,会根据单词的变化指定语态、时态、人称,但在特征提取时我们可能不需要细分到这种地步,所以我们需要还原到原始词以减少维度

from nltk.stem.wordnet import WordNetLemmatizer
lemmatizer = WordNetLemmatizer()
print(lemmatizer.lemmatize('gathering', 'v'))
print(lemmatizer.lemmatize('gathering', 'n'))from nltk.stem import PorterStemmer
stemmer = PorterStemmer()
print(stemmer.stem('gathering'))

前一个我们称之为词干提取,注意到不同词性下gathering有不同的原始词!

现在让我们把三种降维技术综合到一起!

from nltk import word_tokenize
from nltk.stem import PorterStemmer
from nltk.stem.wordnet import WordNetLemmatizer
from nltk import pos_tag
wordnet_tags = ['n', 'v']
corpus = ['He ate the sandwiches','Every sandwich was eaten by him'
]
stemmer = PorterStemmer()
print('Stemmed:', [[stemmer.stem(token) for token in word_tokenize(document)] for document in corpus])def lemmatize(token, tag):if tag[0].lower() in ['n', 'v']:return lemmatizer.lemmatize(token, tag[0].lower())return token
lemmatizer = WordNetLemmatizer()
tagged_corpus = [pos_tag(word_tokenize(document)) for document in corpus]
print('Lemmatized:', [[lemmatize(token, tag) for token, tag in document] for document in tagged_corpus])

注意

显而易见,PorterStemmer类的处理结果出现了错误(如every → everi,was → wa),这是强制转换词性导致的。相比之下,WordNetLemmatizer会根据词性进行转换。在对文档进行word_tokenize时,实际上会得到两个属性,一个是单词形成的token,另一个属性中则包含着单词的词性。

4.3.4 tf-idf权重扩展词包

和类别变量一样,目前来说我们的词袋模型是基于单词出现次数的。假想一下,在一篇篮球新闻报道中会出现大量的basketball,而在篮球商店门口的广告上basketball出现的次数相比肯定是很少的,但两则文本都是以basketball为主题的,为了解决这个问题,我们使用tf-idf技术:
tf(f,d)=f(t,d)∣∣x∣∣tf(f,d)=\frac{f(t,d)}{||x||}tf(f,d)=∣∣x∣∣f(t,d)
等式左边是缩放后的单词频数,右边分子上是单词的真实频数(即实际出现了几次),分母上是该单词对应的频数向量的长度。

类似地,我们还可以使用对数缩放法处理单词频数:
tf(t,d)=1+ln(f(t,d))tf(t,d)=1+ln(f(t,d))tf(t,d)=1+ln(f(t,d))

当在创建TfdfTransformer类的实例时将sublinear_tf关键词设置成True时,该实例会自动计算单词频数的对数缩放值。

那么什么是idf呢?IDF全称为逆文档频率,该技术会考察某一主题特定的停用词,如乒乓球中的上旋球、下旋球,足球中的前锋、后卫等,这些特有词对文档进一步的细分没有帮助,所以我们会适当缩小这一维度的值从而便于同一主题下的文档相似性比较。

idf(t,D)=ln(N1+∣d∈D:t∈d∣)idf(t,D)=ln\left(\frac{N}{1+|d\in D:t \in d|}\right)idf(t,D)=ln(1+dD:tdN)
其中分子是语料库中的文档总数,语料库被命名为D,d值某一文档,t即文档中的单词或说token,分母可以简单理解为语料库中包含某一单词(主题停用词)的文档数目。一个单词的tf-idf值是其单词频数和逆文档指数的乘积。

由于tf-idf值经常用来表示文本,scikit learn中将TfidfTransformer类和CountVectorizer类封装在了一起成为TfidfVectorizer类。

上述算法在scikit-learn的实现如下:

from sklearn.feature_extraction.text import TfidfVectorizercorpus = ['The dog ate a sandwich and I ate a sandwich','the wizard transfigured a sandwich'
]
vectorizer = TfidfVectorizer()
print(vectorizer.fit_transform(corpus).todense())

4.3.5 空间有效特征向量化与哈希技巧

面对大规模文档,继续使用字典显得有点捉襟见肘,因其效率的限制我们接下来将采用哈希技术来优化数据集的存储:

from sklearn.feature_extraction.text import HashingVectorizer
corpus = ['the', 'ate', 'bacon', 'cat']
vectorizer = HashingVectorizer(n_features = 6)
print(vectorizer.fit_transform(corpus).todense())

4.3.6 词向量

Google News语料库下载详见附录2
词向量是一种减轻了词袋模型某些缺点的文本表示法,相比于词袋模型使用标量来表示一个token,而词向量则使用一个向量。向量经常会被压缩,通常包含50~500个维度,这些表示单词的向量处于一个度量空间中,语义相似的单词对应的向量相互也很接近。具体来说,词向量参数化的函数本质上是一个词向量矩阵参数化的查找表,接受一个来自某些语言的token并产出一个向量。
本节将使用gensim库与在谷歌新闻语料库上训练过的word2vec词向量。

import gensim
model = gensim.models.KeyedVectors.load_word2vec_format('G:/GoogleNews-vectors-negative300.bin.gz', binary=True)
embedding = model.get_vector('cat')
print('Dimensions: %s' % embedding.shape)
print(embedding)# 比较两个单词的相似性
print(model.similarity('cat', 'dog'))
print(model.similarity('cat', 'sandwich'))# Palette对于Painter就像是Saddle对于什么呢?
for i in model.most_similar(positive=['saddle', 'painter'], negative=['palette'], topn=3):print(i)

附录

1.NLTK的下载与安装

nltk的百度云链接:
链接:https://pan.baidu.com/s/1GAw8mdbtjdBY3R0Lm5ry_g?pwd=0000
提取码:0000

下载完成后,将压缩包内的文件解压到Python或者Anaconda 3目录下新建的nltk_data文件夹中.

2.Google News语料库的下载与使用

语料库的百度云链接:
链接:https://pan.baidu.com/s/1sR9D9Le7GwHCaG2xOr5LBw?pwd=0000
提取码:0000

下载后放到任意文件夹下,在使用的时候代入该文件的绝对地址,如:

model = gensim.models.KeyedVectors.load_word2vec_format('D:/Files/GoogleNews-vectors-negative300.bin.gz', binary=True)

scikit-learn机器学习 读书笔记(二)相关推荐

  1. Bishop 模式识别与机器学习读书笔记_ch1.1 机器学习概述

    模式识别与机器学习-读书笔记 第一章 机器学习概述(I) 数据模式搜索问题是一个基础性的问题,有着悠久而成功的历史. 16世纪对第谷布拉赫的广泛天文观测使约翰内斯开普勒发现了行星运动的经验定律,从而为 ...

  2. oracle直查和call哪个更快,让oracle跑的更快1读书笔记二

    当前位置:我的异常网» 数据库 » <>读书笔记二 <>读书笔记二 www.myexceptions.net  网友分享于:2013-08-23  浏览:9次 <> ...

  3. 《How Tomcat Works》读书笔记(二)

    <How Tomcat Works>读书笔记(二) 这是<How Tomcat Works>第一二章的读书笔记.第一张主要写了一个静态资源处理的web服务器,第二章加了对ser ...

  4. 3D游戏设计读书笔记二

    3D游戏设计读书笔记二 一.简答题 • 解释 游戏对象(GameObjects) 和 资源(Assets)的区别与联系.   GameObjects是一个具体的实例,Assets是包括诸多游戏素材的资 ...

  5. 《Docker 技术入门与实践》-读书笔记二

    <Docker 技术入门与实践>-读书笔记一 <Docker 技术入门与实践>-读书笔记二 一.数据管理 用户在使用 Docker 的过程中,往往需要能查看容器内应用产生的数据 ...

  6. 《Introduction To Modern Cryptography》读书笔记二

    <Introduction To Modern Cryptography>读书笔记二 本笔记纯粹个人读书习惯与相应见解,内容归纳完全出于个人需要与个人局限,如有修改意见(比如哪儿应该是值得 ...

  7. 机器学习读书笔记(开篇)

    新近到手一本<机器学习实战>(Peter Harringtom),兴奋之余,本着好记性不如烂笔头的真理,打算将读书的过程记录下来,形成读书笔记,重点记录自己所理解的算法思想与应用示例.本人 ...

  8. 《李元芳履职记》读书笔记二 IT技术管理的沟通与团队建设

    <李元芳履职记>读书笔记二 接一 https://blog.csdn.net/qq_45937199/article/details/103305223 IT技术人员从技术岗走向管理岗,所 ...

  9. [Mitchell 机器学习读书笔记]——人工神经网络

    1.简介 神经网络学习方法对于逼近实数值.离散值或向量值的目标函数提供了一种健壮性很强的方法.在现实中,学习解释复杂的现实世界中的传感器数据,人工神经网络(Artificial Neural Netw ...

最新文章

  1. C#和F#默认接口方法更新
  2. python 一份简单的车辆环视全景系统实现图像拼接缝融合
  3. uvc摄像头代码解析7
  4. MySQL 使用SELECT ... FOR UPDATE 做事务写入前的确认(转)
  5. 关于用户升级到MacOS10.10系统后versions崩溃的问题
  6. JAVA I/O 字符输出流简要概括
  7. Kubernetes pod状态出现ImagePullBackOff的原因
  8. 企业实战01_Linux下安装ActiveMQ并设置开机启动
  9. C语言排序方法-----二分插入排序
  10. 怀念本科时代----科学入门的导师肖建华老师
  11. vue3中setup()函数的使用一
  12. Kubernetes Pod 优先级和抢占
  13. Linux之vim常用扩展操作
  14. 数组累加兼eval性能测试
  15. wp 一次简单的攻防训练
  16. Android之按钮点击事件(单击、双击、长按等)
  17. DevOps推广实践总结
  18. 类似淘巴士订票小程序
  19. 摄像头的车牌识别(用hyperlpr的车牌识别,python版本)
  20. 公民身份证号码的编排规则

热门文章

  1. python爬虫笔记四:大众点评店铺信息(字体反爬-静态映射)
  2. 数字藏品如何实现版权保护
  3. Hexo博客SEO优化-百度收录
  4. java 3_4_5判断三角形_小学四年级数学下册【填空题】易错题专项训练
  5. 计算机科学大师唐纳德,计算机科学大师唐纳德.克努特指出,杨辉三角
  6. (2) 机器视觉技术发展的五大趋势
  7. 【项目分析】旅游代购
  8. Profibus网络故障诊断技术总结
  9. 复杂因子秒级计算,文谛资产是这样做到的...
  10. Extrinsic Calibration of a Camera and Laser Range Finder (improves camera calibration)阅读笔记