您的位置:首页 > 编程语言 > Python开发

利用Python gensim基于中文语料建立LSA隐性语义模型

2016-07-07 16:46 525 查看
传统词向量空间模型

对语料库中每个文档进行分词后,将生成一个词典。每个文档对应一个与词典长度一致的向量。若文档中出现某个词,则向量中相应的项目非零。下标index通过将词语输入Hashing函数获得,值一般取该词的TF-IDF。

TF: 词频,在长度为n的文档中某个词出现k次,则有TF=k/n

IDF: 逆文档频率,出现某个词的文档数量d,语料库中一共有N个文档,有IDF=log(N/d).
一般而言如果某个词在整个语料库的每个文档中都出现,例如“这”“那么” 等常用词,对于文本分类的重要性非常弱,使用IDF进行归一化处理的目的是消除停用词(其IDF非常低)的影响。

通过上述方法,将文档映射到向量空间之后,计算当前query与语料库中每个文档的余弦相似度并排序,即可给出与当前query最相似的N个文档。

此方法的一个缺陷是,判断两个文档相似是基于是否出现相同的词语,对于一词多义、近义词等情况无法很好地处理。例如,用户搜索“帝都”,显然是希望返回北京的相关信息,但可能只会返回包含“帝都”这一词语的结果,显然“北京”的结果也应该是用户希望看到的。

LSA的主要思想,是利用线性代数里面的SVD奇异值分解,以便基于语料库归纳出若干主题(topic),同时给出每个主题之中“最重要”的词语。比较两个文本之间的相似,是基于其语义,即是否代表相同或相近的概念,而非传统VSM机械地比较两个文档之间是否有相同的词语。

基本思想:

见维基百科:https://en.wikipedia.org/wiki/Latent_semantic_analysis

下面利用sogou提供的已经分好类的预料(比较旧,2008年)尝试建立一个LSI模型。

文档解压之后,每个类别一个目录,每个文档一个文件,共17900多个文件,类别大致有财经、教育等等。

中文分词采用jiema提供的api,加载gensim完成相应的工作。

代码:
import os
import re
import jieba as ws
import pandas as pd
from gensim import models,corpora
import logging

logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)
documents=[]
labels=[]
class_dir=os.listdir('/home/kim/Reduced/')

#读取语料库
for i in class_dir:
if i.find('C')>-1:
currentpath='/home/kim/Reduced/'+i+'/'
#        print(currentpath)
files=os.listdir(currentpath)
for f in files:
tmp_list=[]
tmp_str=''
try:
file=open(currentpath+f,encoding='gbk')
file_str=file.read()
file_str=re.sub('(\u3000)|(\x00)|(nbsp)','',file_str)#正则处理,去掉一些噪音
doc=''.join(re.sub('[\d\W]','',file_str))
tmp_str='|'.join(ws.cut(doc))
tmp_list=tmp_str.split('|')
labels+=[i]
except:
print('read error: '+currentpath+f)
documents.append(tmp_list)
file.close()

#------------------------------------------------------------------------------
#LSI model: latent semantic indexing model
#------------------------------------------------------------------------------
#https://en.wikipedia.org/wiki/Latent_semantic_analysis
#http://radimrehurek.com/gensim/wiki.html#latent-semantic-analysis
dictionary=corpora.Dictionary(documents)
corpus=[dictionary.doc2bow(doc) for doc in documents]#generate the corpus
tf_idf=models.TfidfModel(corpus)#the constructor

#this may convert the docs into the TF-IDF space.
#Here will convert all docs to TFIDF
corpus_tfidf=tf_idf[corpus]

#train the lsi model
lsi=models.LsiModel(corpus_tfidf,id2word=dictionary,num_topics=9)
topics=lsi.show_topics(num_words=5,log=0)
for tpc in topics:
print(tpc)


运行完毕,输出结果如下:



建模是,设定参数num_topics=9,即指定主题有9个,每个词语前面的数字大致可以理解为该词与主题的相关程度。可以明显地看到,topic[2]大致可以对应到教育主题,topic[3]大致可以对应到财经主题,topic[5]可以对应到体育的主题,etc。

事实上,由于在预处理阶段,没有对停用词进行处理,导致到有很多例如“我”、“你”等词语出现在最后结果之中。但从这个结果来看还勉强过得去。

实际上,在spark mllib里面,也提供了相应的方法,例如TF-IDF的转换,等等,后面将对word2vec模型、以及spark上的实现进行探索。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息