您的位置:首页 > 其它

NLP工具gensim教程中文版(含个人理解与注释,主要为自用,欢迎交流)

2019-02-21 15:41 471 查看
版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/qq_35358452/article/details/87860024

根据官方tutorial总结
首先针对语料库建立它自己的dictionary,官方教程的总体方案是全部变成小写、去掉a/and等连接性词语、去掉只出现一次的词语和空格,但是这不是唯一方案。

The ways to process documents are so varied and application- and language-dependent that I decided to not constrain them by any interface. Instead, a document is represented by the features extracted from it, not by its “surface” string form: how you get to the features is up to you.

在将文本转化为向量的时候,教程中介绍了一个叫做 Bag-of-words model 的方法:

Each key is the word, and each value is the number of occurrences of that word in the given text document.The order of elements is free

通俗来讲,这个方法对语料库(之前已经如上所述预处理过了)中的每一个单词编一个唯一id,每一个单词在map中对应其id。

dictionary = corpora.Dictionary(line.lower().split() for line in open('corpora path'))
stoplist = set('for a of the and to in'.split()) # remove stop words and words that appear only once
stop_ids = [dictionary.token2id[stopword] for stopword in stoplist if stopword in dictionary.token2id]
once_ids = [tokenid for tokenid, docfreq in iteritems(dictionary.dfs) if docfreq == 1]
dictionary.filter_tokens(stop_ids + once_ids)  # remove stop words and words that appear only once
dictionary.compactify()  # remove gaps in id sequence after words that were removed
dictionary.save('dictionary path')

现在dictionary做好了,输入一个待测试的文本,比如:

new_doc = "Human computer interaction"
new_vec = dictionary.doc2bow(new_doc.lower().split())print(new_vec)

在dictionary中,存在Human和computer,id分别是1和0,不存在interaction,所以输出是

[(0, 1), (1, 1)]
,意思是[(第0号id的词, 在本句子中出现了1次), (1, 1与前一个同理)]。

现在应该给语料库一个正式定义了:

In gensim a corpus is simply an object which, when iterated over, returns its documents represented as sparse vectors.

corpus = [[(0, 1.0), (1, 1.0), (2, 1.0)],
[(2, 1.0), (3, 1.0), (4, 1.0), (5, 1.0), (6, 1.0), (8, 1.0)],
[(1, 1.0), (3, 1.0), (4, 1.0), (7, 1.0)],
[(0, 1.0), (4, 2.0), (7, 1.0)],
[(3, 1.0), (5, 1.0), (6, 1.0)],
[(9, 1.0)],
[(9, 1.0), (10, 1.0)],
[(9, 1.0), (10, 1.0), (11, 1.0)],
[(8, 1.0), (10, 1.0), (11, 1.0)]]

也就是说,对于一些句子(样本),在corpus对其编好了号然后给出了它的其中的词语出现的次数。现在假设用于建立字典的语料库特别大,如果把corpus一次性读入内存不太可取,因此可以用python的yield功能,同时注意到教程中把文件中每一行当作一个documen,这个不一定的,你可以根据你的需要在__iter__(self)函数中自行分割每一个document:
(不知道为啥不太会用CSDN编辑python代码,因为有缩进的关系,所以用图片代替了)
相应的解释大家可以看图片中的注释。这里有一个当时点,仅作提醒:教程中提到的字典,就是通过mycorpus.txt(可以理解为训练集)训练出来的为以后有了新的输入之后对其进行向量化的,他是在本文第一段给出的代码中训练好的,它是为每一个单词带上一个编号,他的应用如下,doc2bow()的功能参见上一个图片中的注释。

new_vec = dictionary.doc2bow(new_doc.lower().split())

而图片中提到的MyCorpus(object)函数是可以看作它先用dictionary为他里面的每个单词获取一个编号,然后那些单词进行一些运算之后成为了后面待比对文本的base,也就是后面的文本可以与他进行比较,需要跟上面的那个mycorpus.txt做一个区分

介绍完字典的生成以及用其对输入的文本进行编码(形成向量),教程又介绍了一下将这些东西存储在硬盘上的接口,在此略过。

但是如果用字典对输入的文本做分析的时候,只给出该词的编号以及在一行中出现的次数,并不能很好地体现出一句话中各个词语之间的关系,向量的语义性也得不到很好的体现:

To bring out hidden structure in the corpus, discover relationships between words and use them to describe the documents in a new and (hopefully) more semantic way. To make the document representation more compact. This both improves efficiency (new representation consumes less resources) and efficacy (marginal data trends are ignored, noise-reduction).

因此我们要对已经得到的向量

corpus = [[(0, 1.0), (1, 1.0), (2, 1.0)],
[(2, 1.0), (3, 1.0), (4, 1.0), (5, 1.0), (6, 1.0), (8, 1.0)],

进行转换,对每一个向量加上一个权重,教程中运用到的方法是先用TfidfModel转换,再将输出用LsiModel再转换一次:
一、TfidfModel(term frequency–inverse document frequency)

TF-IDF是一种统计方法,用以评估一字词对于一个文件集或一个语料库中的其中一份文件的重要程度。字词的重要性随着它在文件中出现的次数成正比增加,但同时会随着它在语料库中出现的频率成反比下降。TFIDF的主要思想是:如果某个词或短语在一篇文章中出现的频率TF高,并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分能力,适合用来分类。TFIDF实际上是:TF * IDF,TF词频(Term Frequency),IDF逆向文件频率(Inverse Document Frequency)。TF表示词条在文档d中出现的频率。IDF的主要思想是:如果包含词条t的文档越少,也就是n越小,IDF越大,则说明词条t具有很好的类别区分能力。如果某一类文档C中包含词条t的文档数为m,而其它类包含t的文档总数为k,显然所有包含t的文档数n=m+k,当m大的时候,n也大,按照IDF公式得到的IDF的值会小,就说明该词条t类别区分能力不强。但是实际上,如果一个词条在一个类的文档中频繁出现,则说明该词条能够很好代表这个类的文本的特征,这样的词条应该给它们赋予较高的权重,并选来作为该类文本的特征词以区别与其它类文档。在一份给定的文件里,词频(term frequency,TF)指的是某一个给定的词语在该文件中出现的频率。这个数字是对词数(term count)的归一化,以防止它偏向长的文件。

tfidf = models.TfidfModel(corpus)  # step 1 -- initialize a model

step 1 – initialize a model
经过这一步的处理,tfidf[]已经变成了一个只读的对象,用来将最开始的Bag-of-words vectors转化为含有权重的tfidf vectors。

doc_bow = [(0, 1), (1, 1)]
print(tfidf[doc_bow])
output:[(0, 0.70710678), (1, 0.70710678)]

Or to apply a transformation to a whole corpus:

corpus_tfidf = tfidf[corpus]
for doc in corpus_tfidf:
print(doc)

step 2 – use the model to transform vectors
一、LsiModel(Latent semantic analysis/indexing)

传统向量空间模型使用精确的词匹配,即精确匹配用户输入的词与向量空间中存在的词。比如用户搜索“automobile”,即汽车,传统向量空间模型仅仅会返回包含“automobile”单词的页面,而实际上包含”car”单词的页面也可能是用户所需要的。潜语义分析试图去解决这个问题,它把词和文档都映射到一个潜在语义空间,文档的相似性在这个空间内进行比较。潜语义空间的维度个数可以自己指定,往往比传统向量空间维度更少,所以LSA也是一种降维技术。

什么意思呢?也就是说,“说了或者写了哪些单词”和“真正想表达的意思”之间有很大的区别,比如苹果,可以是水果也可以是公司。但是,LSA的基本假设是,如果两个词多次出现在同一文档中,则这两个词在语义上具有相似性。如果它是公司,含有可能伴随他的有“互联网”、“手机”、“iPhone”等词语,因此,我们希望找到一种模型,能够捕获到单词之间的相关性。如果两个单词之间有很强的相关性,那么当一个单词出现时,往往意味着另一个单词也应该出现(同义词);反之,如果查询语句或者文档中的某个单词和其他单词的相关性都不大,那么这个词很可能表示的是另外一个意思(比如在讨论互联网的文章中,Apple 更可能指的是Apple公司,而不是水果) 。

lsi = models.LsiModel(corpus_tfidf, id2word=dictionary, num_topics=2)  # initialize an LSI transformation
corpus_lsi = lsi[corpus_tfidf]  # create a double wrapper over the original corpus: bow->tfidf->fold-in-lsi

在上面的代码里面,num_topics=2也就是说我们把待测文本分为了两个话题(潜语义),结果如下:

lsi.print_topics(2)
topic #0(1.594): -0.703*"trees" + -0.538*"graph" + -0.402*"minors" + -0.187*"survey" + -0.061*"system" + -0.060*"response" + -0.060*"time" + -0.058*"user" + -0.049*"computer" + -0.035*"interface"
topic #1(1.476): -0.460*"system" + -0.373*"user" + -0.332*"eps" + -0.328*"interface" + -0.320*"response" + -0.320*"time" + -0.293*"computer" + -0.280*"human" + -0.171*"survey" + 0.161*"trees"

从上面的输出结果我们可以看出“trees”, “graph” 和“minors”几个词语之间有关系并且对第一个话题贡献度较大,其他词语对第二个话题贡献度较大

for doc in corpus_lsi:  # both bow->tfidf and tfidf->lsi transformations are actually executed here, on the fly
...     print(doc)
[(0, -0.066), (1, 0.520)] # "Human machine interface for lab abc computer applications"
[(0, -0.197), (1, 0.761)] # "A survey of user opinion of computer system response time"
[(0, -0.090), (1, 0.724)] # "The EPS user interface management system"
[(0, -0.076), (1, 0.632)] # "System and human system engineering testing of EPS"
[(0, -0.102), (1, 0.574)] # "Relation of user perceived response time to error measurement"
[(0, -0.703), (1, -0.161)] # "The generation of random binary unordered trees"
[(0, -0.877), (1, -0.168)] # "The intersection graph of paths in trees"
[(0, -0.910), (1, -0.141)] # "Graph minors IV Widths of trees and well quasi ordering"
[(0, -0.617), (1, 0.054)] # "Graph minors A survey"

从这个结果也可以看出,前五句话与第二个话题关联性更强,后四句话与第一个话题关联性更强。

面重点来了,我们前面做的一切都是为了更好的比较两个文档的相似性,怎么比较呢?下面开始介绍一下:

dictionary = corpora.Dictionary.load('/tmp/deerwester.dict')
corpus = corpora.MmCorpus('/tmp/deerwester.mm')
print(corpus)

首先载入字典dictionary(提供word2id功能)以及过会输入了待测试文本之后需要与其进行比对的语料库corpus(可以理解为进行对比的base吧),

lsi = models.LsiModel(corpus, id2word=dictionary, num_topics=2)

之后建立LsiModel,暂时将corpus区分为两个topic,采用dictionary的编号,

doc = "Human computer interaction"
vec_bow = dictionary.doc2bow(doc.lower().split())
vec_lsi = lsi[vec_bow]  # convert the query to LSI space
print(vec_lsi)
[(0, -0.461821), (1, 0.070028)]

现在假设有一个新文本doc = “Human computer interaction”,vec_bow 将其转为bag-of-wors向量,vec_lsi 将其转为lsi,因为有两个topic,因此这里的意思是doc = "Human computer interaction"这句话与corpus中的第一个topic更相关。但是,它到底与corpus中的哪句话(哪一行)更相关呢,那就需要把所有的corpus内容与"Human computer interaction"都对比一边:

index = similarities.MatrixSimilarity(lsi[corpus])  # transform corpus to LSI space and index it
sims = index[vec_lsi]  # perform a similarity query against the corpus
print(list(enumerate(sims)))  # print (document_number, document_similarity) 2-tuples
[(0, 0.99809301), (1, 0.93748635), (2, 0.99844527), (3, 0.9865886), (4, 0.90755945),
(5, -0.12416792), (6, -0.1063926), (7, -0.098794639), (8, 0.05004178)]

对上面的结果做一下整理:

sims = sorted(enumerate(sims), key=lambda item: -item[1])
print(sims)  # print sorted (document number, similarity score) 2-tuples
[(2, 0.99844527), # The EPS user interface management system
(0, 0.99809301), # Human machine interface for lab abc computer applications
(3, 0.9865886), # System and human system engineering testing of EPS
(1, 0.93748635), # A survey of user opinion of computer system response time
(4, 0.90755945), # Relation of user perceived response time to error measurement
(8, 0.050041795), # Graph minors A survey
(7, -0.098794639), # Graph minors IV Widths of trees and well quasi ordering
(6, -0.1063926), # The intersection graph of paths in trees
(5, -0.12416792)] # The generation of random binary unordered trees

可以看到,"Human computer interaction"这句话与"The EPS user interface management system"关联最大。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐