天然语言处理真实项目实战

前言

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

前提知识和术语解释

若是须要得到更多知识,请自行百度,谷歌。中文资料不是不少,有能力请阅读相关论文资料。java

余弦类似度

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

余弦类似度

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

单位矢量

单位向量是指模等于1的向量。因为是非零向量,单位向量具备肯定的方向。一个非零向量除以它的模,可得所需单位向量。单位向量有无数个。(矢量和向量是同一个意思,Vector,这里习惯用矢量这个词语)github

向量加减

平行四边形定则解决向量加法的方法:将两个向量平移至公共起点,以向量的两条边做平行四边形,结果为公共起点的对角线。平行四边形定则解决向量减法的方法:将两个向量平移至公共起点,以向量的两条边做平行四边形,结果由减向量的终点指向被减向量的终点。算法

image.png数组

向量点积

代数定义设二维空间内有两个向量网络

app

,定义它们的数量积(又叫内积、点积)为如下实数:机器学习

更通常地,n维向量的内积定义以下:

点乘的结果就是两个向量的模相乘,而后再与这两个向量的夹角的余弦值相乘。或者说是两个向量的各个份量分别相乘的结果的和。很明显,点乘的结果就是一个数,这个数对咱们分析这两个向量的特色颇有帮助。若是点乘的结果为0,那么这两个向量互相垂直;若是结果大于0,那么这两个向量的夹角小于90度;若是结果小于0,那么这两个向量的夹角大于90度。

TF-IDF

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

Doc2Vec

在天然语言处理中,一个很重要的技术手段就是将文档转换为一个矢量,这个过程通常是使用gensim这个库进行处理的。gensim官网地址若是你须要Java版本的Doc2Vec:https://github.com/NLPchina/W...

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的速度很快,或是能够用平行化计算减小计算所需的时间。

LinearRegression from sklearn.linear_model import LinearRegression

fit(X, y[, n_jobs]) 对训练集X, y进行训练。是对scipy.linalg.lstsq的封装score(X, y[,]sample_weight) 定义为(1-u/v),其中u = ((y_true - y_pred)2).sum(),而v=((y_true-y_true.mean())2).mean()最好的得分为1.0,通常的得分都比1.0低,得分越低表明结果越差。其中sample_weight为(samples_n,)形状的向量,能够指定对于某些sample的权值,若是以为某些数据比较重要,能够将其的权值设置的大一些。

代码和处理流程 语料库的准备

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

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

关于这个函数的参数介绍,能够参考这里,全英文很是晦涩难懂的介绍:https://radimrehurek.com/gens...

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值,获得最类似的句子。能够看到句向量在对句子的语义表征上仍是至关惊叹的。

clipboard.png

句子类似度结果 类似检索

这里的类似度检索是指,给定一个正面的句子,而后检索和其类似度最大的句子。固然,这里也能够指定一个负面的句子,也就是和这个句子越不类似越好。这里有一个限制,若是正面的句子和负面的句子,进行分词以后,没有一个词语是被训练过的(被训练过的词语,是指语料库里面存在的词语),则没法进行操做。

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

(Negative和Positive相似)

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

infer_vector(doc_words, alpha=0.1, min_alpha=0.0001, steps=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=10, clip_start=0, clip_end=None, indexer=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的变种聚类算法应运而生。

clipboard.png

Mini Batch K-Means

Compute the centroids on X by chunking it into mini-batches.fit拟合操做,实际上就是计算每一个簇的质心。因此说,若是簇只有一个的话,拟合的意义是求出整个数据的质心。predict(X)Predict the closest cluster each sample in X belongs to.predict预测操做,是给出每一个样本属于哪一个簇的结果

训练样本的分类和整理

项目中将全部样本按照时间分为:1年期样本和3年期样本。同时根据其余业务规则进行了分类(分类规则须要保密)。因为收集样本的渠道不一样(不一样的公司,组织提供的样本数据),全部的样本还须要进行Remove Common Factor的操做:1.样本的分类并无按照渠道进行分类,因此这里同一收集渠道的样本,也会被分在不一样的类中2.全部分类样本,例如1年期,3年期的样本,都必须进行Remove Common Factor3.同同样本可能同时存在于不一样分类组里面,由于有些是按照时间分类的,有些是按照业务分类的,分类的维度不一样。

代码的逻辑以下:fit:XX[tag]里面的tag表示收集渠道,XX[tag]表示某个渠道的样本矢量数组:_cf[tag]:表示某个渠道的Common Factor矢量,这里使用np.array(XX[tag]).mean(axis=0)按列求均值得到的。每个渠道有一个Common Factor矢量。remove代码则是将某个渠道里面全部的矢量,都剪去Common Factor矢量(代码有删减,原来代码里面有对于未知渠道的防护代码,这里已经简化)

在咱们的训练样本(document)中,有一个权重(weight)属性,这个属性是和业务有关的,也是这个项目须要进行预测的。例如,有一些用户对于商品的评论,能够看做一个训练样本(document),这个商品的销量能够看做权重属性(weight)。咱们须要训练的模型就是得到一个商品评论和销量的关系模型,利用这个模型可以经过商品评论去预测一个商品的销量。这里假设咱们的权重分为5个级别,-2(无人问津),-1(滞销),0(正常),1(畅销),2(爆款) 分别对应5种销量级别。而后咱们将全部样本经过MiniBatchKMeans分到8个不一样簇里面,注意,这里的簇数和级别数是不同的。另外请注意,训练后的簇,其簇的编号和权重也是没有任何关系的,簇号0-7和权重-2到2,彻底是两个独立的体系。

同时,咱们还须要得到一个训练的得分(score)

评价训练得分的部分使用了余弦原理,经过单位向量的点乘(点积)结果来得到类似度。注意,必定要将两个矢量都单位化,转换为模为1的矢量,这样点乘出来的结果才是余弦值。负分数 = 矢量单位化(待预测矢量 - 簇的权重为正数的矢量均值)点积 单位矢量化簇的正负差

Python语言

推荐经过网络上的 廖雪锋的Python教程 学习python语法

numpy sum

axis:求和的维。

numpy mean

axis:求平均的维。

lambda 和浮点数

python中使用 .1 表明浮点数 0.1 或者 1. 表明浮点数 1.0。缘由是要保证结果的精度,防止程序自动强制转换。

score = lambda X, y: 1.-((y-X)**2).sum()/((y-y.mean())**2).sum() percentile

幾つかの数値データを小さい順に並べたとき、小さい方から数えて全体のX%に位置する値をXパーセンタイルと言います。(数值按照从小到大进行排列,从小的数字开始计算,全体数字的X%的位置,数值是多少)

例えば10人のクラスがあるとして、各生徒のテストの点数が[40, 50, 60, 70, 75, 80, 83, 86, 89, 95]だったとします。その時、下から95%に位置する点数(逆に言うと上位5%に位置する点数)が何点なのか示すものが95パーセンタイルになります。

如下、numpyを使ったサンプルです。

>>> import numpy as np>>> a = np.array([40, 50, 60, 70, 75, 80, 83, 86, 89, 95])>>> np.percentile(a, 95) # 95パーセンタイルを求めます(逆に言うと上位5%に位置する点数)92.299999999999997# 95パーセンタイルは約92.3点であることがわかります>>> np.percentile(a, 30) # 30パーセンタイルを求めます(逆に言うと上位70%に位置する点数)67.0# 30パーセンタイルは67.0点であることがわかります
相关文章
相关标签/搜索