5.3 自然语言处理基础
如果机器学习模型只能操作数值型的数据,那么我们如何将文本转换成数值的表示?这是自然语言处理(NLP)的重点。在我们处理数据之前,需要简要了解一下NLP的原理。
一开始我们不使用从Pocket收集来的数据,而是一个最简化的例子,以确保阐明NLP的工作原理。一旦这些都清楚了,我们就可以将其应用于新闻源的语料库。
我们将从一个包含三句话的小语料库开始。
· The new kitten played with the other kittens
· She ate lunch
· She loved her kitten
我们首先将语料库转换为词袋(BOW)的表示。这里将跳过预处理。将语料库转换为词袋表示,包括获取每个单词及其数量,来创建词条-文档的矩阵。在词条-文档的矩阵中,每个唯一的单词对应于一列,而每个文档对应于一行。两者的交点是这个单词在该文档中出现的次数,如表5-1所示。
表5-1
the | new | kitten | played | with | other | kittens | she | ate | lunch | loved | her | |
1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 |
2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 |
3 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 1 |
请注意,仅仅分析了这三个短句,我们就已经有了12个特征[5]。可以想象,如果处理真实的文档,例如新闻稿,甚至是书籍,那么特征的数量将爆炸式地增长到数十万。为了缓解这个问题,我们可以采取一系列的步骤,删除对分析几乎没有价值的特征。
我们可以采取的第一步是删除停用词。这些单词是如此的普通,它们通常无法告诉你关于文档的内容。常见的英语停用词的示例是“the”、“is”、“at”、“which”和“on”。我们将删除这些词并重新计算词条-文档矩阵,如表5-2所示。
表5-2
new | kitten | played | kittens | ate | lunch | loved | |
1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 |
2 | 0 | 0 | 0 | 0 | 1 | 1 | 0 |
3 | 0 | 1 | 0 | 0 | 0 | 0 | 1 |
如你在表5-2中所见,特征的数量从12个减少到7个。这很棒,但我们可以更进一步。这里可以执行取词干或词形还原来进一步减少特征。请注意在我们的矩阵中,同时存在“kitten”和“kittens”。使用取词干或词形还原的技术,我们可以将这两者合并为“kitten”,如表5-3所示。
表5-3
new | kitten | play | eat | lunch | love | |
1 | 1 | 2 | 1 | 0 | 0 | 0 |
2 | 0 | 0 | 0 | 1 | 1 | 0 |
3 | 0 | 1 | 0 | 0 | 0 | 1 |
我们的新矩阵合并了“kittens”和“kitten”,不过这里还进行了其他的修改。我们去掉了“played”和“loved”的后缀,“ate”变成了“eat”。为什么呢? 这就是词形还原所做的事情。如果你还记得小学的语法课,我们学过从带词尾的形式转变为词的基本形式。现在,如果词形还原是将一个词变换为它的基本形式,那什么是取词干呢?取词干也有同样的目标,不过它使用的方法没有那么复杂。这种方法有时可以产生虚构的单词而不是实际的基本形式。例如,在词形还原中,如果你变换词“ponies”,你会得到“pony”;而使用取词干的技术,你会得到“poni”。
现在,让我们进一步对矩阵应用另一个变换。到目前为止,我们使用了每个单词的简单计数,但是可以采用某个算法以做得更好,它就像数据的过滤器,以提升对于每个文档而言更为特殊的单词。该算法称为词频-逆文档频率或tf-idf。
我们为矩阵中的每个词条计算tf-idf的值。这里来算几个例子。对于文档1中的“new”一词,词频只是1。逆文档频率计算为文档总数除以出现该词的文档数,再取log。对于“new”来说就是log(3/1),或0.4471。所以对于完整的tf-idf值,我们使用tf × idf,在这里它是1 × 0.4471,或者就是0.4471。对于文档1中的单词“kitten”,tf-idf是2 × log(3/2),或0.3522。
为剩余的词条和文档完成同样的操作,我们获得了表5-4。
表5-4
new | kitten | play | eat | lunch | love | |
1 | 0.4471 | 0.3522 | 0.4471 | 0 | 0 | 0 |
2 | 0 | 0 | 0 | 0.4471 | 0.4471 | 0 |
3 | 0 | 0.1761 | 0 | 0 | 0 | 0.4471 |
为什么要做这些?为了获得较高的tf-idf值,一个词条需要在较少的文档中,出现较高的次数。这样,我们可以认为文件由具有高tf-idf值的词条所表示。
使用目前的数据框,我们将训练集转换为tf-idf矩阵。
from sklearn.feature_extraction.text import TfidfVectorizer vect = TfidfVectorizer(ngram_range=(1,3), stop_words='english', min_df=3) tv = vect.fit_transform(df['text'])
通过这三行,我们将所有文档转换为tf-idf向量。有几点需要注意。我们传入了一些参数:ngram_range、stop_words和 min_df。让我们逐个来讨论。
首先,ngram_range表示文档是如何被分词的。在之前的例子中,我们将每个单词作为分词,但在这里我们使用每一个、每二个到每三个词组成的序列作为分词。以第二句话为例,“She ate lunch.”此时忽略停用词。那么这句话的ngram将是:“she”、“she ate”、“she ate lunch”、“ate”、“ate lunch”和“lunch”。
接下来的选项是stop_words。我们传入“English”来删除所有的英语停用词。如前所述,这将删除所有缺乏信息含量的词条。
最后的选项是min_df。这里会删除所有文档频率少于三的单词。加入此操作会移除那些非常罕见的词条,并减少矩阵的规模。
现在我们的文章语料库是可供模型操作的数值格式,下面继续将其输送给分类器。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论