词袋模型是将文本转换成向量的一种方式,且容易实现,本文将详细地阐述词袋模型以及如何实现词袋模型。

文本存在的问题

在对文本进行建模的时候存在一个问题,就是“混乱”,因为像机器学习算法通常更喜欢固定长度的输入、输出,但是文本是不定长的。机器学习算法不能直接处理纯文本,要使用文本的话,就必须把它转换成数值,尤其是数值向量。这个就叫做特征提取或者特征编码。而文本数据的特征提取,其中一种简单且流行的方法就是词袋模型。

什么是词袋?

词袋是一篇文档中单词出现的文本表示,它包含两个信息:

1. 一个已知单词构成的字典

2. 一种已知单词出现的度量

它之所以称为词“袋”,是因为它只关心单词是否出现,而且关于文档中的单词的顺序和结构信息都忽略掉了。直观的感觉是,如果文档具有相似的内容,那么它们就是相似的。此外,仅从内容我们就可以了解文档的一些含义。

词袋模型可以很简单,也可以很复杂。这主要取决于如何设计由已知单词构成的词典以及如何对已知单词的出现进行评分。

一个词袋模型样例

下面用一个例子来具体地解释词袋模型。

第1步:收集数据

It was the best of times,

it was the worst of times,

it was the age of wisdom,

it was the age of foolishness,

我们将上面四句话作为语料,并且每一句话都作为一个文档,即语料中共有4篇文档,我们的目的就是将这四个文档分别表示成一个定长的向量。

第2步:设计词汇表

根据语料,我们可以统计出语料中出现过的单词(忽略大小写和标点符号):

  • “it”
  • “was
  • “the”
  • “best”
  • “of”
  • “times”
  • “worst”
  • “age”
  • “wisdom”
  • “foolishness”

那么这就是上述所给语料库构成的词典。

第3步:生成文档向量

这一步的目标就是将每一篇文档转换成一个向量,用于机器学习模型的输入或者输出。因为我们得到的词典总共有10个单词,我们就使用一个长度为10的向量来表示文档。其中,向量中每个位置的值为该位置对应单词的评分。其中一种最简单的评分方式就是:将该位置的单词的评分作为布尔值,1表示该位置对应的单词在文档中出现了;0则表示该位置对应的单词没有出现。这种方式也叫one-hot编码。

那么,以第1个文档“*It was the best of times*”为例,这篇文档的评分如下:

  • “it” = 1
  • “was = 1
  • “the” = 1
  • “best” = 1
  • “of” = 1
  • “times” = 1
  • “worst” = 0
  • “age” = 0
  • “wisdom” = 0
  • “foolishness” = 0

因此,第1篇文档生成的向量为:

[1, 1, 1, 1, 1, 1, 0, 0, 0, 0]

同理,剩下三个文档生成的向量如下:

'it was the worst of times'=[1, 1, 1, 0, 1, 1, 1, 0, 0, 0]

'it was the age of wisdom'=[1, 1, 1, 0, 1, 0, 0, 1, 1, 0]

'it was the age of foolishness'=[1, 1, 1, 0, 1, 0, 0, 1, 0, 1]

对于与已知单词的词汇表重叠但可能包含词汇表之外的单词的新文档,仍然可以进行编码,只对已知单词的出现进行评分,忽略未知单词。

改进词汇表

在上面的描述中,文档向量的长度与词汇表的大小一致,随着词汇表增大,文档向量的维度同样也会增大。那么,对于一个非常大的语料库,比如语料库是成千上万本书,那么词汇表的大小或者向量的维度或许将达到上百万。此外,每一篇文档中可能只有极少数单词出现在词汇表中。那么这就会导致向量中会有很多0,称为稀疏向量或稀疏表示。但是,稀疏向量在计算时需要大量的内存和计算资源。因此,在使用词袋模型时,需要减小词汇表的大小。一种方式就是对原始文本进行清理,有一些简单的文本清理技术,例如:

1. 忽略大小写;

2. 忽略标点符号;

3. 忽略那些出现频率高但没有包含很多信息的单词,如“a”,“of”等,这类词称为停用词(stop words)。;

4. 恢复拼写错误的单词;

5. 使用词干提取算法将单词简化为词干(例如从“playing”变成“play”)。

另一种更复杂的方法是创建一个由单词组构成的词汇表,这既改变了词汇表的范围,又允许词汇表从文档中获取更多的含义,这种方法称为n-gram。

在这个方法中,每个单词(符号)被称为“元”,那么创建由两个单词组成的对构成的词汇表称为二元模型(bigram model)。同样,只有出现在语料库中的二元组被建模,而不是所有可能的二元组。

比如前面的文档“*It was the best of times*”的二元组如下:

“it was”

“was the”

“the best”

“best of”

“of times”

同样经常使用的一种n-gram模型是三元模型(trigram model),它是由连续的三个单词构成的。以上面的例子为例,它的三元组表示:

“it was the”

“was the best”

“the best of”

“best of times”

像文本分类任务,通常一个简单的二元方法要比一元词袋模型更好。

单词评分

一旦选择了一个词表,那么就需要对文档中的词汇进行评分。在前面我们已经讲过了一种评分方式:文档中出现了词汇表中的单词,那么该单词对应的位置的值为1;没有出现就为0。这也是one-hot向量的形式。

除了上述评分方式之外,还有一些其他的评分方式,比如:

1. 计数(counts):统计一篇文档中每个单词出现的次数;

2. 频率(frequencies):计算文档中每个单词在所有单词中出现的频率(一篇文档中某个单词出现的次数/该篇文档的单词总数)。

TF-IDF

TF-IDF是NLP中一种常用的统计方法,用于评估一个词语对于一篇文档或一个语料库中的其中一篇文档的重要程度,通常用于提取文本的特征,即关键词。词语的重要性与它在文档中出现的次数成正比,但同时与它在语料库中出现的频率成反比。TF-IDF的计算如下:

$$TF-IDF=TF*IDF$$

TF为词频,即一个词语在文档中的出现频率,假设一个词语在整个文档中出现了m次,而整个文档有n个词语,则TF的值为m/n。

IDF为逆文本频率,假设整个语料有n篇文档,而一个词语在k篇文档中出现,则某个单词w的IDF值为

$$IDF(w)=log\frac{\text{文档总数}}{\text{出现词汇w的文档总数+1}}=log\frac{n}{k+1}$$

词袋模型的局限性

通过上面的描述,词袋模型也存在很多局限性。比如稀疏性,通过词袋模型得到的文本表示是稀疏的,这就使得后续的计算消耗非常巨大,时间复杂度和空间复杂度都很大。同时,因为在建立词袋模型时忽略了文本中单词的顺序和结构信息。所以在很多情况下会导致文本语义表达不准确。比如“我打了你”和“你打了我”,这两句话的意思是相反的,但是它们的词袋模型表示是一样的。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐