Gensim使用小解

Topic modelling for humans

   看着gensim这个标题都觉得霸气,从文本预处理,特征提出到主题聚类等,基本上包含了文本处理的所有功能。

Corpora and Vector Spaces

  语料与向量空间,这一节主要讲如何把文本从词变为bag-of-word。中文的话无非是中间加入了分词这一步骤。之前用过jieba,觉得效果还不错。

停用词git上有一个中文预料预处理

documents = ["做人要谦虚,但做事不要谦虚,毛遂自荐,让别人看到你,知道你的存在,知道你的能力,这样你才有机会,别人才会把重任交给你。",
             "天下没有好赚的钱,千万不要一口吃个胖子,先从小钱赚起吧",
             "不管从事什么行业,一定要相同行业或不同行业的人吸收新知识,而且要用请教的态度。",
             "犯错,就诚实地认错,并立刻改错,不要狡辩。",              
             ".要想成功,就要以失败为老师,在失败中汲取教训。",
             ".一定要守时!守时是对别人的尊重。",
             ".用真心诚意打动别人,让任何人为你做事。",
             "全力以赴迎接种种挑战,不要把困难看成是在整你。",
             "这一句没什么意思"]

f=open('stopwords.txt', encoding='gbk')
lines=f.readline()
stoplst=list(map(lambda x:x.strip('\n'), lines))
texts = [[word for word in jieba.lcut(document) if word not in stop lst] for document in documents]

但是发现停用词完全没有被过滤。后来发现,在stoplst中每个元素后面都有一个\n。
分词结果如下

[['做人','谦虚','做事','不要','谦虚','毛遂自荐','看到','知道','存在','知道','能力','机会','会','重任','交给'],
 ['天下', '没有', '好赚', '钱', '千万', '不要', '一口', '吃个', '胖子', '先', '从小', '钱', '赚起'],
 ['从事', '行业', '一定', '相同', '行业', '不同', '行业', '吸收', '新', '知识', '请教', '态度'],
 ['犯错', '诚实', '认错', '立刻', '改错', '不要', '狡辩'],
 ['.', '想', '成功', '失败', '老师', '失败', '中', '汲取', '教训'],
 ['.', '一定', '守时', '守时', '尊重'],
 ['.', '真心诚意', '打动', '任何人', '做事'],
 ['全力以赴', '迎接', '种种', '挑战', '不要', '困难', '看成', '整'],
 ['一句', '没什么', '意思']]

文中说了,文本的特征提取方法有很多,并且很重要,这里提到了一个garbage in, garbage out意思就是你算法再牛逼,你的输入有问题,输出还是不行,所以,怎么选取一个能够有效表述文本的特征非常重要。然后这里选择的最简单的bag-of-words,并且,为了方便表示,使用corpora.Dictionary 用id来替代文本,这里是构建一个字典,下面的doc2bow是该对象的一个方法,即将文本使用这个字典描述,字典中不存在的直接忽略。

from collections import defaultdict
frequency = defaultdict(int)
for text in texts:
    for token in text:
        frequency[token] += 1
# texts = [[token for token in text if frequency[token] > 1]
#           for text in texts]
dictionary = corpora.Dictionary(texts)
dictionary.save('/tmp/deerwester.dict')  # store the dictionary, for future reference
print(dictionary)
print(dictionary.token2id)
{'做人': 0, '谦虚': 1, '做事': 2, '不要': 3, '毛遂自荐': 4, '看到': 5, '知道': 6, '存在': 7, '能力': 8, '机会': 9, '会': 10, '重任': 11, '交给': 12, '天下': 13, '没有': 14} #截取了一部分

由于都是短文本,我把频次小于1去掉那句注释了。

new_doc = "我的存在对你是真心诚意的"#新文本的转化
new_vec = dictionary.doc2bow(jieba.lcut(new_doc))
print(new_vec)
[(7, 1), (50, 1)]
corpus = [dictionary.doc2bow(text) for text in texts] #都转化为ID表示
corpora.MmCorpus.serialize('/tmp/deerwester.mm', corpus)  # 保存到硬盘
print(corpus)

Corpus Streaming – One Document at a Time

这一节主要是针对大文本文件,构建一个对象使其成为一个生产器。
>>> class MyCorpus(object):
>>>     def __iter__(self):
>>>         for line in open('mycorpus.txt'):
>>>             # assume there's one document per line, tokens separated by whitespace
>>>             yield dictionary.doc2bow(line.lower().split())
>>> from six import iteritems
>>> # collect statistics about all tokens
>>> dictionary = corpora.Dictionary(line.lower().split() for line in open('mycorpus.txt'))
>>> # 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
>>> print(dictionary)

虽然结果同样是list,但是corpus对内存更加友好,因为作为生成器,内存中每次只处理一行。

Corpus Formats

gensim有很多将空间向量语义存到磁盘的方法

>>> corpora.MmCorpus.serialize('/tmp/corpus.mm', corpus)
>>> corpora.SvmLightCorpus.serialize('/tmp/corpus.svmlight', corpus)
>>> corpora.BleiCorpus.serialize('/tmp/corpus.lda-c', corpus)
>>> corpora.LowCorpus.serialize('/tmp/corpus.low', corpus)

load的话也很简单,但是corpus是一个文件流

>>> corpus = corpora.MmCorpus('/tmp/corpus.mm')

Compatibility with NumPy and SciPy

与numpy和scipy之间矩阵的转换,也是,现在python哪个机器学习相关的库不跟这两个打交道

>>> import gensim
>>> import numpy as np
>>> numpy_matrix = np.random.randint(10, size=[5,2])  # random matrix as an example
>>> corpus = gensim.matutils.Dense2Corpus(numpy_matrix)
>>> numpy_matrix = gensim.matutils.corpus2dense(corpus, num_terms=number_of_corpus_features)

>>> import scipy.sparse
>>> scipy_sparse_matrix = scipy.sparse.random(5,2)  # random sparse matrix as example
>>> corpus = gensim.matutils.Sparse2Corpus(scipy_sparse_matrix)
>>> scipy_csc_matrix = gensim.matutils.corpus2csc(corpus)

Topics and Transformations

Creating a transformation

from gensim import corpora, models, similarities
tfidf = models.TfidfModel(corpus) # step 1 -- initialize a model

不同的转换需要不同的初始化参数,对于tfidf,就只是遍历所有文本一遍建立文本频率信息。训练譬如LDA和LSA,则需要更多的参数和时间。

Transforming vectors

doc_bow = [(0, 1), (1, 1)]
print(tfidf[doc_bow]) # step 2 -- use the model to transform vectors
corpus_tfidf = tfidf[corpus]

利用已经建立的tfidf模型,得到新的文本的tfidf向量。并将原文本全部转化为tfidf。之前以为tfidf = models.TfidfModel(corpus)后得到的tfidf就是由corpus得到的tfidf矩阵,后来才知道,与其他拟合模型一样,它返回的相当于一个带参数的模型。
我们知道,corpus如果从文件中读取的话是一个stream,model[corpus] only creates a wrapper around the old corpus document stream,如果要对transform后的对象多次迭代的话,建议先序列化到磁盘。
并且transform可以序列化,即对上一个transformed的对象继续使用。

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
for doc in corpus_lsi: # both bow->tfidf and tfidf->lsi 转化实际上在这里才开始执行
     print(doc)

lsi.save('/tmp/model.lsi') # same for tfidf, lda, ...
lsi = models.LsiModel.load('/tmp/model.lsi')

训练得到的模型可以保存,避免每次重复训练。

Available transformations

gensim中包含的转换算法,感觉每个都够研究一壶的
tfidf
LSI
Random Projections, RP
LDA
Hierarchical Dirichlet Process, HDP

Similarity Queries

我们之前bag-of-words, transform都是为了有一个能够衡量文本间距离的标准, (such as a user query vs. indexed documents).

Initializing query structures

index = similarities.MatrixSimilarity(lsi[corpus]) # transform corpus to LSI space and index it

首先,建立自己的语料库
similarities.MatrixSimilarity 会读入所有数据,因此对内存要求较大。
当内存大小不满足时,可以使用 similarities.Similarity class,这个类在固定的内存中运行,通过将索引分散到磁盘上的多个文件中,称为碎片。它内部调用similarities.MatrixSimilarity and similarities.SparseMatrixSimilarity,速度很快,就是有点复杂(这一部分后面使用后会加上一些内容)

index.save('/tmp/deerwester.index')
index = similarities.MatrixSimilarity.load('/tmp/deerwester.index')

这么不好计算,那就肯定可以把模型存下来咯

你可能感兴趣的:(nlp)