【sklearn文本特征提取】词袋模型/稀疏表示/停用词/TF-IDF模型

1. 词袋模型 (Bag of Words, BOW)

文本分析是机器学习算法的一个主要应用领域。然而,原始数据的这些符号序列不能直接提供给算法进行训练,因为大多数算法期望的是固定大小的数字特征向量,而不是可变长度的原始文本。

为了解决这个问题,scikit-learn提供了从文本内容中提取数字特征的常见方法,即:

  1. tokenizing: 标记字符串并为每个可能的token提供整数id,例如使用空白和标点作为token分隔符;(分词标记)
  2. counting: 统计每个文档中出现的token次数;(统计词频)
  3. normalizing: 通过减少大多数样本/文档中都会出现的一般性标记来进行标准化和加权。(标准化/归一化)

在此方案中,特征和样本定义如下:

每个独立token出现的频率(已标准化或未标准化)作为特征。
给定文档的所有token频率的向量作为多元样本。

因此,文本语料库可以由矩阵表示,每一行代表一个文本,每一列代表一个token(例如一个单词)。

向量化:将文本集合转换为数字特征向量的一般过程。
这种方法(tokenizing,counting和normalizing)称为“词袋”或“n-gram”模型。 即只通过单词频率来描述文档,而完全忽略文档中单词的相对位置信息。

2. 稀疏表示

由于大多数文本通常只使用语料库中的很小一部分单词,因此生成的矩阵将具有许多为零的特征值(通常超过99%)。

例如,有一个文本集合,包含一万个文本(邮件等),它使用的词汇表大约为十万个词,而其中每个文档单独使用的词只有100到1000个。

为了能够将这样的矩阵存储在内存中并且加快矩阵/向量的代数运算,实现上通常会使用稀疏表示,在scipy.sparse包中有实现方法。

3. 常用的Vectorizer的用法

CountVectorizer在单个类中同时实现tokenizing和counting:

from sklearn.feature_extraction.text import CountVectorizer

该模型具有许多参数,但是默认值是相当合理的:

vectorizer = CountVectorizer()
vectorizer

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 sparse matrix of type '<class 'numpy.int64'>'
with 19 stored elements in Compressed Sparse Row format>

其默认参数配置是通过提取单词(至少2个字母)来标记字符串。也可以通过显式请求来查看这一步骤:

analyze = vectorizer.build_analyzer()
analyze("This is a text document to analyze.")

['this', 'is', 'text', 'document', 'to', 'analyze']

在拟合过程中,将由分析器找到的每一项分配一个唯一的整数索引,该索引对应于所得矩阵中的一列。 可以按以下方式检索这些列:

vectorizer.get_feature_names()

['and', 'document', 'first', 'is', 'one', 'second', 'the', 'third', 'this']

X.toarray()

array([[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]])

从特征名到列索引的反向映射存储在Vectorizer的vocabulary_属性中:

vectorizer.vocabulary_.get('first')

2

因此,在之后对transform方法的调用中,训练语料库中未出现的单词将被完全忽略:

vectorizer.transform(['Something completely new.']).toarray()

array([[0, 0, 0, 0, 0, 0, 0, 0, 0]])

注意,在前一语料库中,第一个文档和最后一个文档具有完全相同的词,因此被编码为同样的向量。 但这就失去了最后一个文档是疑问句的信息。
为了保留一些局部信息,我们可以提取单词的1-gram(单个单词)以外的2-gram信息:

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

因此,这个Vectorizer提取的词汇量要更大,而且现在可以解决局部定位模式中的编码歧义:

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]])

特别是疑问句形式 “Is this” 仅出现在最后一个文档中:

feature_index = bigram_vectorizer.vocabulary_.get('is this')
X_2[:, feature_index]

array([0, 0, 0, 1])

4. 停用词

停用词是指诸如“and”,“the”,“him”之类的词,它们被认为在表示文本内容方面没有提供任何信息,可以将其删除以避免其影响预测效果。
但是,有时候,类似的单词对于预测很有用,例如在对写作风格或语言个性进行分类时。

请谨慎选择停用词列表。 通用的停用词列表也可能包含对某些特定任务(例如计算机领域)非常有用的词。

此外,还应该确保停用词列表的预处理和标记化与Vectorizer中使用的预处理和标记化相同。
CountVectorizer的默认标记器将单词"we've"分为we和ve,因此,如果“we've”在stop_words中,而ve则没有,则在转换后的文本中会保留ve。
我们的Vectorizer将尝试识别并警告某些不一致之处。

TF-IDF模型

在大型文本语料库中,会经常出现一些单词(例如英语中的“ the”,“ a”,“ is”),而这些单词几乎不包含关于文档实际内容的有意义的信息。
如果我们将直接计数数据不加处理地提供给分类器,那么那些高频词会影响低频但更有意义的词的出现概率。

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

tf表示词频,而tf–idf表示词频乘以逆文档频率:

\(\text{tf-idf(t,d)}=\text{tf(t,d)} \times \text{idf(t)}\)

TfidfTransformer的默认参数为,TfidfTransformer(norm='l2', use_idf=True, smooth_idf=True, sublinear_tf=False)。

词频,即一个单词在文档中出现的频率,乘以idf:

\(\text{idf}(t) = \log{\frac{1 + n}{1+\text{df}(t)}} + 1\)

n是文本集中文本总数,df(t)是包含t词的文本数,然后将所得的tf-idf向量通过欧几里得范数归一化:

\(v_{norm} = \frac{v}{||v||_2} = \frac{v}{\sqrt{v{_1}^2 + v{_2}^2 + \dots + v{_n}^2}}\)

这最初是信息检索的词加权方案,作为搜索引擎结果的排名方法,目前也在文档分类和聚类中广泛应用。

以下各节包含进一步的说明和示例,这些示例说明了如何精确计算tf-idf,以及在scikit-learn的TfidfTransformer和TfidfVectorizer中怎样计算的。
与标准教科书的符号稍微不同,idf定义为:

\(\text{idf}(t) = \log{\frac{n}{1+\text{df}(t)}}.\)

在TfidfTransformer和TfidfVectorizer中设置smooth_idf=False,将“ 1”计数添加到IDF中,而不是IDF的分母中:

\(\text{idf}(t) = \log{\frac{n}{\text{df}(t)}} + 1\)

这一规范化由TfidfTransformer类实现:

from sklearn.feature_extraction.text import TfidfTransformer

transformer = TfidfTransformer(smooth_idf=False)
transformer

TfidfTransformer(norm='l2', smooth_idf=False, sublinear_tf=False, use_idf=True)

让我们以以下的统计数为例。 第一个词出现的概率100%,因此它的出现没有什么代表性。 其他两个词仅在不到50%的时间内出现,因此可能更能代表文档的内容:

counts = [[3, 0, 1],
          [2, 0, 0],
          [3, 0, 0],
          [4, 0, 0],
          [3, 2, 0],
          [3, 0, 2]]
tfidf = transformer.fit_transform(counts)
tfidf

<6x3 sparse matrix of type '<class 'numpy.float64'>'
with 9 stored elements in Compressed Sparse Row format>

tfidf.toarray()

array([[0.81940995, 0. , 0.57320793],
[1. , 0. , 0. ],
[1. , 0. , 0. ],
[1. , 0. , 0. ],
[0.47330339, 0.88089948, 0. ],
[0.58149261, 0. , 0.81355169]])

每行均经过单位欧几里得范数计算以进行标准化:

\(v_{norm} = \frac{v}{||v||_2} = \frac{v}{\sqrt{v{_1}^2 + v{_2}^2 + \dots + v{_n}^2}}\)

例如,我们可以如下计算counts数组中第一个文档中第一项的tf-idf:

\(n = 6\)

\(\text{df}(t)_{\text{term1}} = 6\)

\(\text{idf}(t)_{\text{term1}} = \log \frac{n}{\text{df}(t)} + 1 = \log(1)+1 = 1\)

\(\text{tf-idf}_{\text{term1}} = \text{tf} \times \text{idf} = 3 \times 1 = 3\)

现在,如果我们对文档中剩余的2个词重复此计算,我们将得到:

\(\text{tf-idf}_{\text{term2}} = 0 \times (\log(6/1)+1) = 0\)

\(\text{tf-idf}_{\text{term3}} = 1 \times (\log(6/2)+1) \approx 2.0986\)

原始的tf-idf向量:

\(\text{tf-idf}_{\text{raw}} = [3, 0, 2.0986].\)

然后,应用欧几里得(L2)范数,我们为文本1获得以下tf-idfs:

\(\frac{[3, 0, 2.0986]}{\sqrt{\big(3^2 + 0^2 + 2.0986^2\big)}} = [ 0.819, 0, 0.573].\)

此外,默认参数smooth_idf = True将“ 1”添加到分子和分母,就好像看到一个额外的文档恰好包含一次集合中的每个术语一次,从而避免了分母为零的问题:

\(\text{idf}(t) = \log{\frac{1 + n}{1+\text{df}(t)}} + 1\)

使用此修改,文档1中第3项的tf-idf更改为1.8473:

\(\text{tf-idf}_{\text{term3}} = 1 \times \log(7/3)+1 \approx 1.8473\)

并且L2归一化的tf-idf变为:

\(\frac{[3, 0, 1.8473]}{\sqrt{\big(3^2 + 0^2 + 1.8473^2\big)}} = [0.8515, 0, 0.5243]\)

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

array([[0.85151335, 0. , 0.52433293],
[1. , 0. , 0. ],
[1. , 0. , 0. ],
[1. , 0. , 0. ],
[0.55422893, 0.83236428, 0. ],
[0.63035731, 0. , 0.77630514]])

由fit方法调用计算出的每个特征的权重存储在model属性中:

transformer.idf_

array([1. , 2.25276297, 1.84729786])

由于tf–idf通常用于文本特征,因此还有另一个名为TfidfVectorizer的类,它将CountVectorizer和TfidfTransformer的所有选项组合在一个模型中:

from sklearn.feature_extraction.text import TfidfVectorizer

vectorizer = TfidfVectorizer()
vectorizer.fit_transform(corpus)

<4x9 sparse matrix of type '<class 'numpy.float64'>'
with 19 stored elements in Compressed Sparse Row format>

尽管tf–idf归一化通常非常有用,但是在某些情况下,二进制频率标记法可能会提供更好的特性。 这可以通过使用CountVectorizer的二进制参数来实现。
特别是,某些估计量(例如Bernoulli Naive Bayes)明确地对离散的布尔型随机变量建模。 同样,很短的文本可能带有tf–idf值的噪声,而二进制出现信息则更稳定。

通常,调整特征提取参数的最佳方法是使用交叉验证的网格搜索,例如用分类器将特征提取器进行流水线化。

参考资料

sklearn.feature_extraction.text文档

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
tf-idf模型是一种用于文本处理和分析的技术。它的主要思想是将文本中的每个汇作为一个特征,通过计算汇在文档中的重要程度来进行特征提取表示。它结合了频(term frequency)和逆文档频率(inverse document frequency)的计算方法。 在tf-idf模型中,表示了某个汇在文档中出现的频率,逆文档频率表示了该汇在整个文集中的重要程度。通过将频和逆文档频率相乘,可以得到某个汇在文档中的tf-idf值。通过对一篇文档中的所有汇计算tf-idf值,可以得到该文档的特征向量表示。 jieba是一款常用的中文分工具,可以将中文文本按照语进行分割。在文本情感分类任务中,jieba可以被用于对文本进行分预处理,将长句子切分成短语,并去除等。分后的文本可以作为特征的基础,用于情感分类任务。 文本情感分类是指通过对文本的分析和理解,将其归类为积极、消极或中性等情感类别。在进行情感分类时,可以利用tf-idf模型提取文本特征向量表示,并将其输入到机器学习模型中进行分类训练。根据文本中的汇出现情况和tf-idf值,模型可以学习到不同汇与情感类别之间的关联,从而进行文本情感的分类判断。 综上所述,tf-idf模型和jieba在文本分类任务中扮演着重要的角色。它们分别用于提取文本特征向量表示和中文文本预处理,为文本情感分类任务提供了基础。通过结合这两种技术,可以建立有效的文本情感分类模型

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值