您的位置:首页 > 其它

「词嵌入」在自然语言处理中扮演什么角色?一文搞懂Word Embeddings的背后原理

2017-10-15 00:00 2727 查看




原文来源:DATASCIENCE

作者:Ruslana Dalinina

「机器人圈」编译:嗯~阿童木呀、多啦A亮

「机器人圈」正式更名为「雷克世界」,后台回复「雷克世界」查看更多详情。


介绍

相信大家都清楚,自然语言处理(NLP)所涉及的广阔领域使得我们能够理解从在线评论到音频录制这样大量语言数据的模式。但在数据科学家真正挖掘出一个NLP问题之前,他或她必须为此奠定基础,从而帮助模型对即将遇到的不同语言单位有所了解。

词嵌入(Word embeddings)是一组广泛应用于预测NLP建模的特征工程技术,特别是在深度学习应用中的使用更为显著。词嵌入是将词的稀疏向量表示转换为密集、连续的向量空间,使你能够识别单词和短语之间的相似性,而这一点很大程度上依赖于它们的语境。

在本文中,我将详细阐述一下词嵌入背后的原理,并演示如何使用这些技术对来自亚马逊的500000份评论数据创建相似词汇的集群。你可以下载数据集(https://www.kaggle.com/snap/amazon-fine-food-reviews)来进行追踪。

词嵌入:它们是如何运作的?

在典型的词袋(bag-of-words)模型中,每个单词都被认为是一个唯一的标记,与其他单词毫无关联。例如,即使“salt(盐)”和“seasoning(调味料)”平时都是高频地出现在相同的语境或是句子中,也将被分配一个唯一的ID。词嵌入是一系列特征工程技术,它将稀疏的词向量映射到基于周围语境的连续空间中。话句话说,你可以将此过程视为将高维向量词表示嵌入到一个较低维的空间中。

而这样的向量表示比较单词或短语提供了便利属性。例如,如果“salt”和“seasoning”出现在相同的语境中,那么模型将表明“salt”在概念上更接近于“seasoning”,而不是“chair(椅子)”。

现如今有几种用于构建词嵌入表示的模型。谷歌的word2vec是最为广泛使用的实现之一,而这主要得益于它的训练速度和性能。Word2vec是一个预测模型,这意味着它并不是像LDA(latent
Dirichlet allocation)那样需要进行单词计数,而是被训练为从邻近词的语境中预测目标词。该模型首先使用独热编码(one-hot-encoding)对每个单词进行编码,然后使用权重矩阵将其馈送到隐藏层;该过程的输出则是目标单词。词嵌入向量实际上是该拟合模型的权重。为了更好地进行说明,这里有一个简单的视觉图:
 



实际上,Word2vec有两种“风格”的词嵌入模型:连续的词袋(CBOW)和跳格式。CBOW实现会在目标单词周围出现一个滑动窗口,以便于做出预测。而另一方面,跳格式模型则是截然相反的——它会预测出给定目标单词的语境周边的单词。有关跳格式模型的更多信息,请查阅此篇学术论文(https://arxiv.org/abs/1310.4546)。

入门

为什么有那么多人对词嵌入如此感兴趣呢?这主要是因为词嵌入在深度学习的多种任务中有着非常广泛的应用,如情绪分析、语法分析、命名称识别等。除此之外,它们还可以用于:

•通过基于语境的保存单词与单词之间的相似性,提供一种更为复杂的方法来表示数字空间中的单词。

•提供单词或短语之间的相似度的衡量标准。

•用作分类任务中的特征。

•提高模型性能。

使用词嵌入可以发现许多有趣的关系,最著名的例子莫过于此了:king
- man + woman = queen。所以,请继续在Amazon Fine Foods评论数据集中进行词嵌入操作吧!

可以先从越多语料库开始,我将使用一个面向DataScience.com客户的模块,该模块被称之为“客户手册”,其中包含常见文本处理和建模任务的代码,例如删除或阻止不良字符。它也可以用于主题建模和意见挖掘任务。

# imports
%matplotlib inline
 
import os
import pandas as pd
import numpy
import matplotlib.pyplot as plt
import string
import re
from gensim import corpora
from gensim.models import Phrases
from nltk.corpus import stopwords
from nltk.stem.porter import PorterStemmer
 
from ds_voc.text_processing import TextProcessing
 
# sample for speed
raw_df = raw_df.sample(frac=0.1,  replace=False)
print raw_df.shape
 
# grab review text
raw = list(raw_df['Text'])
print len(raw)
 
先标注我们的样本,并做一般的清理步骤:删除不好的字符,过滤单词和干扰:
 
# word2vec expexts a list of list: each document is a list of tokens
te = TextProcessing()
 
cleaned = [te.default_clean(d) for d in raw]
sentences = [te.stop_and_stem(c) for c in cleaned]
 
现在我们已经准备好适应一个模型了。这里我们使用gensim实现:
 
from gensim.models import Word2Vec
 
model = Word2Vec(sentences=sentences, # tokenized senteces, list of list of strings
                 size=300,  # size of embedding vectors
                 workers=4, # how many threads?
                 min_count=20, # minimum frequency per token, filtering rare words
                 sample=0.05, # weight of downsampling common words
                 sg = 0, # should we use skip-gram? if 0, then cbow
                 iter=5,
                 hs = 0
        )
 
X = model[model.wv.vocab]
 
瞧!这很简单。现在,你可以问这个模型有什么问题?回想一下,在相似情景下发生的词将被认为是相似的,从而形成“集群”。 从简单的例子开始,通过检查模型认为类似于“花生”的什么样的词语:
 
print (model.most_similar('peanut'))
 
[(u'butter', 0.9887357950210571), (u'fruit', 0.9589880108833313), (u'crunchi', 0.9448184967041016), (u'potato', 0.9327490329742432), (u'textur', 0.9302218556404114),
(u'nut', 0.9176014065742493), (u'tasti', 0.9175000190734863), (u'sweet', 0.9135239124298096), (u'appl', 0.9122942686080933), (u'soft', 0.9103059768676758)]
 
不错,最相似的标记当然是“黄油”,其他的标记也很直观。然而,“水果”和“苹果”可能是客户提到果酱和花生酱时扩展的结果。让我们再举几个例子:
 
print (model.most_similar('coffee'))
 
[(u'k', 0.8691866397857666), (u'starbuck', 0.862629771232605), (u'keurig', 0.85813969373703), (u'decaf', 0.8456668853759766), (u'blend', 0.840221643447876), (u'bold',
0.8374124765396118), (u'cup', 0.8330360651016235), (u'brew', 0.8262926340103149), (u'espresso', 0.8225802183151245), (u'roast', 0.812541127204895)]
 
print (model.most_similar('spice'))
 
[(u'refresh', 0.9925233721733093), (u'caramel', 0.9756978750228882), (u'pepper', 0.9739495515823364), (u'cherri', 0.9737452268600464), (u'slightli', 0.9729464054107666),
(u'cinnamon', 0.9727376699447632), (u'lemon', 0.9724155068397522), (u'blueberri', 0.9717040061950684), (u'sour', 0.971449613571167), (u'cocoa', 0.9712052345275879)]
 
请注意,即使“焦糖苹果香料”是一个受欢迎的组合,但与“香料”最相似的词语是“刷新”和“焦糖”。你可以扩展类比,不仅可以在上下文中包含多个词,还可以排除某些词。我对富含蛋白质的零食很感兴趣,但我不想服用蛋白质补充剂:
 
print (model.most_similar(['snack', 'protein'], negative=['supplement']))
 
这是模型得出来的结果:
 
[(u'chip', 0.7655218839645386), (u'bar', 0.7496042251586914), (u'potato', 0.7473998069763184), (u'peanut', 0.741823136806488), (u'feel', 0.7318717241287231), (u'cereal',
0.7217452526092529), (u'nut', 0.716484546661377), (u'butter', 0.7104200124740601), (u'healthi', 0.7084594964981079), (u'low', 0.7055443525314331)]
 
该模型发现,“薯条”,“酒吧”,“花生”,“坚果”和“健康”等词汇与“零食”和“蛋白质”相同处在同一词群中,但与“补充品”的词群不同。
 
当然,这些都是简单的例子,但别忘了我们在一个小样本的评论中训练了该模型。我建议你扩展数据集,以构建更强大的词嵌入。
 
可视化词向量
 
为了可视化所得到的单词嵌入,我们可以使用降维技术t-SNE,它可以将所得到的嵌入向量投影到二维中:
 
# visualize food data
from sklearn.manifold import TSNE
 
tsne = TSNE(n_components=2)
X_tsne = tsne.fit_transform(X)
 
plt.rcParams['figure.figsize'] = [10, 10]
plt.scatter(X_tsne[:, 0], X_tsne[:, 1])
plt.show()
 



我们可以看到一些集群形成。我们来标记每一个点,看看所得到的集群。你还可以使用散景库(bokeh library)https://bokeh.pydata.org/en/latest/进行交互式绘图,以便进行缩放。
 
from bokeh.plotting import figure, show
from bokeh.io import push_notebook, output_notebook
from bokeh.models import ColumnDataSource, LabelSet
 
def interactive_tsne(text_labels, tsne_array):
    '''makes an interactive scatter plot with text labels for each point'''
 
    # define a dataframe to be used by bokeh context
    bokeh_df = pd.DataFrame(tsne_array, text_labels, columns=['x','y'])
    bokeh_df['text_labels'] = bokeh_df.index
 
    # interactive controls to include to the plot
    TOOLS="hover, zoom_in, zoom_out, box_zoom, undo, redo, reset, box_select"
 
    p = figure(tools=TOOLS, plot_width=700, plot_height=700)
 
    # define data source for the plot
    source = ColumnDataSource(bokeh_df)
 
    # scatter plot
    p.scatter('x', 'y', source=source, fill_alpha=0.6,
              fill_color="#8724B5",
              line_color=None)
 
    # text labels
    labels = LabelSet(x='x', y='y', text='text_labels', y_offset=8,
                      text_font_size="8pt", text_color="#555555",
                      source=source, text_align='center')
 
    p.add_layout(labels)
 
    # show plot inline
    output_notebook()
    show(p)
 
其中一些更具直观的意义,如左下角包含decaf,bean和french的集群:
  



附加提示
 
我们还可以通过在模型中添加二进制和/或部分语音标签来改进词嵌入。在同一个单词可能具有多重含义的情况下,词性标注可能很有用。例如,seasoning可以是名词也可以是动词,并且根据词性的不同而具有不同的含义。
 
sent_w_pos = [nltk.pos_tag(d) for d in sentences]
sents = [[tup[0]+tup[1] for tup in d] for d in sent_w_pos]
 
model_pos = Word2Vec(sentences=sents,
                 size=300,
                 workers=4,
                 min_count=20,
                 sample=0.05,
                 sg = 0,
                 hs=0,
                 iter=5
        )
 
 
X = model_pos[model_pos.wv.vocab]
 
我们还可以在我们的模型中添加二进制对象,以便将频繁的单词对分组:
 
bigrams = Phrases(sentences)
 
model = Word2Vec(sentences=bigrams[sentences],
                 size=300,
                 workers=4,
                 min_count=20,
                 sample=0.05,
                 sg = 0,
                 iter=5,
                 hs = 0
        )
 
X = model[model.wv.vocab]
 
结论
 
现在,你对词嵌入有了一些基本的了解,并可以使用gensim中的word2vec生成向量。这个有用的技术应该在你的NLP工具箱中,因为它可以在各种建模任务中派上用场。欲了解更多信息,请看DataScience.com平台的演示,查看我们的客户手册,如客户手册的语音和建模资源。

回复「转载」获得授权,微信搜索「ROBO_AI」关注公众号



中国人工智能产业创新联盟于2017年6月21日成立,超200家成员共推AI发展,相关动态:

中新网:中国人工智能产业创新联盟成立

ChinaDaily:China forms 1st AI alliance
证券时报:中国人工智能产业创新联盟成立 启动四大工程搭建产业生态“梁柱”

工信部网站:中国人工智能产业创新联盟与贵阳市政府、英特尔签署战略合作备忘录


点击下图加入联盟







关注“雷克世界”后不要忘记置顶

我们还在搜狐新闻、雷克世界官网、腾讯新闻、网易新闻、一点资讯、天天快报、今日头条、雪球财经……

↓↓↓点击阅读原文查看中国人工智能产业创新联盟手册
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: