自然语言处理真实项目实战(20170818)

Posted 中和软件技术推进

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了自然语言处理真实项目实战(20170818)相关的知识,希望对你有一定的参考价值。

前言

本文根据实际项目撰写,由于项目保密要求,源代码将进行一定程度的删减。
本文撰写的目的是进行公司培训,请勿以任何形式进行转载。
由于是日语项目,用到的分词软件等,在中文任务中需要替换为相应的中文分词软件。例如结巴分词 : https://github.com/fxsjy/jieba

前提知识和术语解释

如果需要获得更多知识,请自行百度,谷歌。中文资料不是很多,有能力请阅读相关论文资料。

余弦相似度

余弦相似度,又称为余弦相似性,是通过计算两个向量的夹角余弦值来评估他们的相似度。余弦相似度将向量根据坐标值,绘制到向量空间中,如最常见的二维空间。


余弦相似度

将向量根据坐标值,绘制到向量空间中。如最常见的二维空间。 
求得他们的夹角,并得出夹角对应的余弦值,此余弦值就可以用来表征,这两个向量的相似性。夹角越小,余弦值越接近于1,它们的方向更加吻合,则越相似。

TF-IDF

TF-IDF是一种统计方法,用以评估一字词对于一个文件集或一个语料库中的其中一份文件的重要程度。字词的重要性随着它在文件中出现的次数成正比增加,但同时会随着它在语料库中出现的频率成反比下降。TF-IDF加权的各种形式常被搜索引擎应用,作为文件与用户查询之间相关程度的度量或评级。除了TF-IDF以外,因特网上的搜索引擎还会使用基于链接分析的评级方法,以确定文件在搜寻结果中出现的顺序。

Doc2Vec

Token

Token在词法分析中是标记的意思。自然语言处理中,一般来说,Token代表“词”。自然语言预处理中,一个很重要的步骤就是将你收集的句子进行分词,将一个句子分解成“词”的列表。

交叉验证

交叉验证(Cross validation),有时亦称循环估计, 是一种统计学上将数据样本切割成较小子集的实用方法。于是可以先在一个子集上做分析, 而其它子集则用来做后续对此分析的确认及验证。 一开始的子集被称为训练集。而其它的子集则被称为验证集或测试集。交叉验证是一种评估统计分析、机器学习算法对独立于训练数据的数据集的泛化能力(generalize)
least-one-out cross-validation(loocv)
假设dataset中有n个样本,那LOOCV也就是n-CV,意思是每个样本单独作为一次测试集,剩余n-1个样本则做为训练集。
优点:
1)每一回合中几乎所有的样本皆用于训练model,因此最接近母体样本的分布,估测所得的generalization error比较可靠。
2)实验过程中没有随机因素会影响实验数据,确保实验过程是可以被复制的。
但LOOCV的缺点则是计算成本高,为需要建立的models数量与总样本数量相同,当总样本数量相当多时,LOOCV在实作上便有困难,除非每次训练model的速度很快,或是可以用平行化计算减少计算所需的时间。

代码和处理流程

语料库的准备

语料库的准备,就是将你准备好的文章库,转换为一个语料库。
你的文章一般会被保存为TaggedDocument,也就是带有标签的文档。
一篇文章对应着一个TaggedDocument对象。
TaggedDocument里面存放的是Token列表和Tag:
其中Token列表就是将文章通过分词软件分成的词语的列表,Tag这里保存着原来文章的编号。
下面这个代码中 tdocs变量表示一个TaggedDocument数组。

注意:在gensim以前版本中TaggedDocument是LabeledSentence

corpus = Doc2Vec(tdocs, dm=1, dm_mean=1,
                 size=300, window=8, min_count=2, workers=4, iter=20)
corpus.save(os.path.join(WORK_DIR, 'base-pv_dm.mdl'))

关于这个函数的参数介绍,可以参考这里,全英文非常晦涩难懂的介绍:
https://radimrehurek.com/gensim/models/doc2vec.html

dm defines the training algorithm. By default (dm=1), ‘distributed memory’ (PV-DM) is used. Otherwise, distributed bag of words (PV-DBOW) is employed.
dm:定义了训练的算法,默认值为1,使用 ‘distributed memory’方法,不然则使用分布式的“bag of words” 方法。(dm,应该是doc model的意思,文档模型,这个需要进一步调查)
size is the dimensionality of the feature vectors.
size:是向量的维度,本项目维度设定是300。维度这个参数也是需要通过大量实验获得最佳的值。
dm_mean = if 0 (default), use the sum of the context word vectors. If 1, use the mean. Only applies when dm is used in non-concatenative mode.
dm_mean:如果是默认值0,则使用上下文向量的和(SUM),如果是1的话,则使用上下文向量的平均值。这个仅仅在dm使用non-concatenative的模式才发生效果。
workers = use this many worker threads to train the model (=faster training with multicore machines).
如果是多核处理器,这里可以指定并行数
iter = number of iterations (epochs) over the corpus. The default inherited from Word2Vec is 5, but values of 10 or 20 are common in published ‘Paragraph Vector’ experiments.
迭代次数:默认的迭代次数是5,但是最佳实践应该是10或者20.
min_count = ignore all words with total frequency lower than this.
如果出现频率少于min_count,则忽略
window is the maximum distance between the predicted word and context words used for prediction within a document.
window是被预测词语和上下文词语在同一个文档中的最大的距离。

语料库也是支持序列化操作的,语料库可以保存为磁盘上的文件:

Save the object to file (also see load).
fname_or_handle is either a string specifying the file name to save to, or an open file-like object which can be written to. If the object is a file handle, no special array handling will be performed; all attributes will be saved to the same file.

语料库建成之后,就可以进行一些有趣的检索了。
例如参考文档 [Algorithm & NLP] 文本深度表示模型——word2vec&doc2vec词向量模型 中的句子相似度实验:

下面是sentence2vec的结果示例。先利用中文sentence语料训练句向量,然后通过计算句向量之间的cosine值,得到最相似的句子。可以看到句向量在对句子的语义表征上还是相当惊叹的。



句子相似度结果

相似检索

这里的相似度检索是指,给定一个正面的句子,然后检索和其相似度最大的句子。
当然,这里也可以指定一个负面的句子,也就是和这个句子越不相似越好。
这里有一个限制,如果正面的句子和负面的句子,进行分词之后,没有一个词语是被训练过的(被训练过的词语,是指语料库里面存在的词语),则无法进行操作。

具体在求相似度的操作之前,检索用向量需要进行一下处理。
假设positive变量是一个数组,数组里面存放着正面的Token。
corpus[token]表示token的矢量,这里对矢量进行按列求和,结果是一个和token维度一样的矢量。换句话说,就是将多个矢量合并为单个矢量。(Token矢量的求和矢量)
然后将上面那个“Token矢量的求和矢量”,和新的positive的推测矢量进行相加,获得一个新的"求相似度用矢量"

(Negative和Positive类似)

    p = np.array([ corpus[token] for token in positive ]).sum(axis=0)
    p = p + corpus.infer_vector(positive, steps=20)
    n = np.array([ corpus[token] for token in negative ]).sum(axis=0)
    n = n + corpus.infer_vector(negative, steps=20)

在语料库对象(Document Model)中有一个很有用的方法infer_vector,这个方法可以基于当前的文档模型快速,将一个文档转换(按照模型推测)成一个矢量。

infer_vector
(doc_wordsalpha=0.1min_alpha=0.0001steps=5)
Infer a vector for given post-bulk training document.
Document should be a list of (word) tokens.

在机器学习界,有两种机器学习方式,一种是Online的,一种是Offline的。Online的方式,模型可以实时更新,新的样本会被实时进行训练,训练结果也实时反映到模型中去。Offline的方式,如果有新的样本,则需要将新老样本放在一起,重新进行训练。这里的话,模型无法进行Online的训练,所以新的样本,只是基于训练好的模型,被转换(推测 Infer,有些类似于预测Predict)为一个矢量。

相似度计算的核心方法是most_similar

most_similar
(positive=[]negative=[]topn=10clip_start=0clip_end=Noneindexer=None)
Find the top-N most similar docvecs known from training. Positive docs contribute positively towards the similarity, negative docs negatively.
This method computes cosine similarity between a simple mean of the projection weight vectors of the given docs. Docs may be specified as vectors, integer indexes of trained docvecs, or if the documents were originally presented with string tags, by the corresponding tags.
The ‘clip_start’ and ‘clip_end’ allow limiting results to a particular contiguous range of the underlying doctag_syn0norm vectors. (This may be useful if the ordering there was chosen to be significant, such as more popular tag IDs in lower indexes.)
寻找最相似的N个文档。正面(Positive)文档向相似度贡献正面的值,负面(Negative)文档贡献负面的值。这个方法通过计算给定文章的矢量的加权平均值的余弦相似度来给出结果。可以通过矢量,被训练过的文档矢量的下标,或者原始的字符串标签来指定文档(正面或者负面文档)。
‘clip_start’ 和 ‘clip_end’则是指定了相似度检索的范围。

官方文档其实说明的不是很清楚,很多地方还是不容易理解。
topn这个参数应该没有问题,你想返回最相似的多少个,这里就指定多少即可。
对于positive和nagative的指定,首先明确一下,这里必须是一个数组,即使只有一个值,也必须是数组。
positive和nagative数组里面的值,可以是:
1.具体的文档的矢量
2.被训练过的文档的下标
3.文档的Tag字符。(本项目里面的Tag就是文档的编号)
具体到这个项目中,Positive则是上文提到的"求相似度用矢量"
‘clip_start’ 和 ‘clip_end’则是指定了相似度检索的范围,这个一般是用来限定检索范围,例如只想在1年或者3年的资料中进行检索。

情感模型建立

MiniBatchKMeans

情感分析是建立在文档的聚类基础上的。由于计算量比较巨大,项目使用的是MiniBatchKMeans。
在有效减少计算时间的同时,也能保证计算误差在可接受范围中。
项目中使用的是Leave-One-Out Cross Validation,每次将一个样本作为测试集,一共进行n次交叉验证。

K-Means算法是常用的聚类算法,但其算法本身存在一定的问题,例如在大数据量下的计算时间过长就是一个重要问题。为此,Mini Batch K-Means,这个基于K-Means的变种聚类算法应运而生。



Mini Batch K-Means

Python语言

numpy sum

axis:求和的维。

>>> np.sum([0.5, 1.5])2.0>>> np.sum([0.5, 0.7, 0.2, 1.5], dtype=np.int32)1>>> np.sum([[0, 1], [0, 5]])6>>> np.sum([[0, 1], [0, 5]], axis=0)
array([0, 6])>>> np.sum([[0, 1], [0, 5]], axis=1)
array([1, 5])

参考文档

数学之美:14章 余弦定理和新闻的分类 (吴军,第二版)
TF-IDF与余弦相似性的应用(一):自动提取关键词
TF-IDF与余弦相似性的应用(二):找出相似文章
Sentiment Analysis Using Doc2Vec
[Algorithm & NLP] 文本深度表示模型——word2vec&doc2vec词向量模型
【転職会議】クチコミをword2vecで自然言語処理して会社を分類してみる
适合大数据的聚类算法Mini Batch K-Means
K-means算法及文本聚类实践


以上是关于自然语言处理真实项目实战(20170818)的主要内容,如果未能解决你的问题,请参考以下文章

腾讯架构师带我写代码 —— vue真实企业实战分享

Java编程思想(20170818)

真实项目开发中高并发实战经验总结

实话实说:中文自然语言处理的N个真实情况

高端实战 Python数据分析与机器学习实战 Numpy/Pandas/Matplotlib等常用库

项目实战 | 月薪3w的大牛为你整理的真实项目开发流程