sklearn 《Text feature extraction》笔记

官方教程见:
https://scikit-learn.org/stable/modules/feature_extraction.html#text-feature-extraction
6.2.3节

1 The Bag of Words representation(词带表示法)

文本分析是机器学习算法的一个主要应用领域。然而原始数据、符号序列不能直接反馈给算法本身,因为大多数算法希望得到的是固定大小的数字特征向量,而不是长度可变的原始文本文档。

为了解决这个问题,scikit-learn提供了最常见的从文本内容中提取数字特征的实用工具,分别是:

  • 把字符串转为标记(token),并为每个可能的标记提供一个整数id,例如使用空格和标点符号作为标记分隔符。
  • 计算每个文档中标记的出现次数。
  • 把出现在样本或文档的主要内容中的标记进行标准化,并按照重要性递减的次序赋权值。

因此,一个文档的语料库可以用一个矩阵来表示,每个文档有一行,语料库中出现的每个标记(如单词)有一列。

我们称向量化为将文本文档集合转化为数字特征向量的一般过程。这种特定的策略(标记化、计数和归一化)被称为 “词袋”(Bag of Words)或 "n-grams袋 "表示法。文档由词的出现次数来描述,而完全忽略词在文档中的相对位置信息。

2 Sparsity(稀疏化)

由于大多数文档通常会使用语料库中使用的单词的一个很小的子集,因此产生的矩阵将有许多特征值为零(通常超过99%)。

例如,一个由10000个短文文档(如电子邮件)组成的集合,这个集合使用的词汇量总大小在10万个不同的单词左右,而每个文档将单独使用100到1000个不同的单词。

为了能够在内存中存储这样一个矩阵,同时也为了加快代数运算矩阵/向量的速度,实现通常会使用稀疏表示法,比如scipy.sparse包中的实现。

3 Common Vectorizer usage(常见的向量器用法)

CountVectorizer这个类在一个类中同时实现了文档的标记化(tokenization)和标记的出现次数计数(occurrence counting):

from sklearn.feature_extraction.text import CountVectorizer

这个模块有很多参数,但是默认值是相当合理的(详情请看参考文档):

vectorizer = CountVectorizer()
print(vectorizer)

# output:
CountVectorizer(analyzer='word', binary=False, decode_error='strict',
        dtype=<class 'numpy.int64'>, encoding='utf-8', input='content',
        lowercase=True, max_df=1.0, max_features=None, min_df=1,
        ngram_range=(1, 1), preprocessor=None, stop_words=None,
        strip_accents=None, token_pattern='(?u)\\b\\w\\w+\\b',
        tokenizer=None, vocabulary=None)

接下来我们尝试用它对一个小规模的文档语料库进行标记化,并对词汇的出现次数进行计数:

corpus = [
    'This is the first document.',
    'This is the second second document.',
    'And the third one.',
    'Is this the first document?',
]
X = vectorizer.fit_transform(corpus)
# X 是一个以三元组形式存储的稀疏矩阵,表示的是一个4x9的稀疏矩阵
print(X)
print(X.shape)
print(type(X))
print(vectorizer.get_feature_names())
print(X.toarray())
print(vectorizer.vocabulary_.get('document'))

# output:
  (0, 1)	1
  (0, 2)	1
  (0, 6)	1
  (0, 3)	1
  (0, 8)	1
  (1, 5)	2
  (1, 1)	1
  (1, 6)	1
  (1, 3)	1
  (1, 8)	1
  (2, 4)	1
  (2, 7)	1
  (2, 0)	1
  (2, 6)	1
  (3, 1)	1
  (3, 2)	1
  (3, 6)	1
  (3, 3)	1
  (3, 8)	1
(4, 9)
<class 'scipy.sparse.csr.csr_matrix'>
['and', 'document', 'first', 'is', 'one', 'second', 'the', 'third', 'this']
[[0 1 1 1 0 0 1 0 1]
 [0 1 0 1 0 2 1 0 1]
 [1 0 0 0 1 0 1 1 0]
 [0 1 1 1 0 0 1 0 1]]
 8

默认的配置是通过提取至少两个字母的单词来标记字符串。这一步的具体功能可以明确要求:

analyze = vectorizer.build_analyzer()
print(analyze("This is a text document to analyze.") == (
    ['this', 'is', 'text', 'document', 'to', 'analyze']))

# output:
True

在训练语料中没有看到的词,在未来调用转换方法时将完全被忽略:

>>> vectorizer.transform(['Something completely new.']).toarray()
array([[0, 0, 0, 0, 0, 0, 0, 0, 0]]...)

注意,在上一个语料库中,第一个文档和最后一个文档的词汇是完全相同的,只有is和this的顺序不同,因此这两个文档被编码成了完全相等的向量。这样一来,我们失去了最后一个文档是一个疑问句的这一信息。为了保留一些局部的排序信息,我们可以在1-grams(单个单词为提取对象)的基础上额外的提取2-grams:

bigram_vectorizer = CountVectorizer(ngram_range=(1, 2), token_pattern=r'\b\w+\b', min_df=1)
analyze = bigram_vectorizer.build_analyzer()
print(analyze('Bi-grams are cool!'))

# output:
['bi', 'grams', 'are', 'cool', 'bi grams', 'grams are', 'are cool']

这样一来,2-grams向量器提取出的词汇矩阵比之前的更大,但是解决了在 local positioning模式下编码二义性的问题:

>>> X_2 = bigram_vectorizer.fit_transform(corpus).toarray()
>>> X_2
array([[0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0],
       [0, 0, 1, 0, 0, 1, 1, 0, 0, 2, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0],
       [1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0],
       [0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1]]...)

3.1 Using stop words(停用词)

停顿词是指 “而”、“该”、"他 "等词,这些词被认为在表示文本内容方面没有信息,为了避免被理解为预测的信号,可以将其删除。但有时,类似的词对预测是有用的,比如在对写作风格或个性进行分类时。

在模块提供的“英语”停用词列表不是通用的、一刀切的解决方案,有些任务可能需要一个更针对性的解决方案,更多信息见[NQY18]。

请谨慎选择停用词表。流行的停用词表可能包括对某些任务来说信息量很大的词。

4 Tf–idf term weighting(Tf-IDF术语加权)

在一个庞大的文本语料库中,有些词会非常频繁地出现(如英语中的 “the”、“a”、"is "等),因此关于文档的实际内容的有意义信息很少。如果我们将直接计数的数据直接输入到分类器中,那么这些非常频繁的词汇就会掩盖掉比较罕见但更有趣的词汇的频率。

为了将计数特征重新加权为适合分类器使用的浮点值,通常会使用 tf-idf 变换。

其中,Tf 的意思是term-frequency(词频),即在一个文档内某个词条总共出现的次数,tf-idf 的意思是 term-frequency 倍的 inverse document-frequency(两个量相乘):
在这里插入图片描述
使用 TfidfTransformer 的默认设置:
TfidfTransformer(norm=‘l2’, use_idf=True, smooth_idf=True, sublinear_tf=False)
tf 将与 idf 相乘,其中,idf 的运算公式是:
在这里插入图片描述
其中 n 是语料库中的文档数量,df(t) 是含有词条 t 的文档的数量。

输出出来的 tf-idf 向量接着会使用欧几里得范数来标准化:
在这里插入图片描述
这原本是一种为信息检索而开发的术语加权方案(作为搜索引擎结果的排名功能),在文档分类和聚类中也得到了很好的应用。

下面的章节包含了进一步的解释和例子,说明了tf-idfs的具体计算方法,以及scikit-learn的TfidfTransformer和TfidfVectorizer中计算出的tf-idfs与标准教科书中定义idf的符号略有不同,其中教科书的定义:
在这里插入图片描述
在TfidfTransformer和TfidfVectorizer中,在smooth_idf=False的情况下,"1 "计数会加到idf中,而不是idf的分母:
在这里插入图片描述
这种标准化由 TfidfTransformer 类实现:

from sklearn.feature_extraction.text import TfidfTransformer

counts = [[3, 0, 1],
          [2, 0, 0],
          [3, 0, 0],
          [4, 0, 0],
          [3, 2, 0],
          [3, 0, 2]]

transformer = TfidfTransformer()
transformer.fit_transform(counts).toarray()

通过调用 fit 方法计算得到的每个特征的权重保存在模块的一个属性里(?这仨特征的权重的计算公式是什么?):

transformer.idf_

由于tf-idf非常常用于文本特征,所以还有一个叫做TfidfVectorizer的类,它将CountVectorizer和TfidfTransformer的所有选项结合在一个模型中:

from sklearn.feature_extraction.text import TfidfVectorizer
vectorizer = TfidfVectorizer()
vectorizer.fit_transform(corpus).toarray()
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值