在之前的实验中,我们利用LDA库来实现了lda, 并且采用二种特征表述方法,一种是直接统计词频的方法,一种是利用TF-IDF来作为特征,并且在有限的测试集上取得了较为理想的效果,当然,这个效果是否真的好,我们需要持怀疑态度哈,需要进一步的验证,这才是严谨的科研态度啊,不管不管,我现在就任性的默认为它能用~~
现在我们需要考虑利用gensim库中的LDA方法,当然,他们都说,学习最好的文档,应该是官方的API和文档,好吧,我承认,在我不懂别人代码的时候,我还是会去查一下的~~gensim中的LDA的实现也有上述二种特征的表述。在这里,我们也是采用二种方式来解决。
实验的代码如下:
# -*- coding:utf-8 -*-
from nltk.tokenize import RegexpTokenizer
from stop_words import get_stop_words
from nltk.stem.porter import PorterStemmer
from gensim import corpora, models
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
if __name__ == "__main__":
corpus = [] # 存储文档
tokens = [] # 存储文档中的单词
# 读取文档的操作
for line in open('a.txt','r').readlines():
if '\xef\xbb\xbf' in line:
line = line.replace('\xef\xbb\xbf', ' ')
corpus.append(line.strip())
print corpus
# 去标点符号,去截止词的操作
en_stop = get_stop_words('en') # 利用Pypi的stop_words包,需要去掉stop_words
# # 提取主干的词语的操作
# p_stemmer = PorterStemmer()
# 分词的操作
tokenizer = RegexpTokenizer(r'\w+')
for text in corpus:
raw = text.lower()
token = tokenizer.tokenize(raw)
stop_remove_token = [word for word in token if word not in en_stop]
# stem_token = [p_stemmer.stem(word) for word in stop_remove_token]
tokens.append(stop_remove_token)
# print tokens
# 得到文档-单词矩阵 (直接利用统计词频得到特征)
dictionary = corpora.Dictionary(tokens) # 得到单词的ID,统计单词出现的次数以及统计信息
# print dictionary.token2id # 可以得到单词的id信息
# print type(dictionary) # 得到的是gensim.corpora.dictionary.Dictionary的class类型
texts = [dictionary.doc2bow(text) for text in tokens] # 将dictionary转化为一个词袋,得到文档-单词矩阵
# # 直接利用词频作为特征来进行处理
# lda_model = models.ldamodel.LdaModel(texts, num_topics=3, id2word=dictionary, passes=500)
# print lda_model.print_topics(num_topics=3,num_words=4)
# corpus_lda = lda_model[texts]
# for doc in corpus_lda:
# print doc
# 利用tf-idf来做为特征进行处理
texts_tf_idf = models.TfidfModel(texts)[texts] # 文档的tf-idf形式(训练加转换的模式)
# # for text in texts_tf_idf: # 逐行打印得到每篇文档的每个单词的TD-IDF的特征值
# # print text
# lda_tf_idf = models.LdaModel(texts_tf_idf, num_topics=3, id2word=dictionary, update_every=0, passes=200)
# print lda_tf_idf.print_topics(num_topics=3,num_words=4)
# # doc_topic = [a for a in lda_tf_idf[texts_tf_idf]]
# # for topic_id in range(3):
# # print "topic:{}".format(topic_id+1)
# # print lda_tf_idf.show_topic(topic_id)
# corpus_lda_tfidf = lda_tf_idf[texts_tf_idf]
# for doc in corpus_lda_tfidf:
# print doc
# 利用lsi做主题分类的情况
print "**************LSI*************"
lsi = models.lsimodel.LsiModel(corpus=texts, id2word=dictionary, num_topics=3) # 初始化一个LSI转换
texts_lsi = lsi[texts_tf_idf] # 对其在向量空间进行转换
print lsi.print_topics(num_topics=3, num_words=4)
for doc in texts_lsi:
print doc
# 利用LDA做主题分类的情况
print "**************LDA*************"
lda = models.ldamodel.LdaModel(corpus=texts, id2word=dictionary, num_topics=3,update_every=0,passes=20)
texts_lda = lda[texts_tf_idf]
print lda.print_topics(num_topics=3, num_words=4)
for doc1 in texts_lda:
print doc1
测试的例子同样取之前的八条,对结果的分析如下:
呜呜,看到结果之后,我的感受就是没有好好的看API,所以处理的特别不优雅啊,看起来好麻烦啊,还是应该好好瞅瞅官方的文档啊,不然,分析的好恼火呀·~
[(0, u'0.063*"chemic" + 0.058*"prepar" + 0.056*"attack" + 0.047*"potenti"'), (1, u'0.050*"us" + 0.041*"love" + 0.039*"global" + 0.038*"salahuddin"'), (2, u'0.041*"us" + 0.041*"salahuddin" + 0.040*"terrorist" + 0.035*"global"')]
[(0, 0.90658676065083843), (1, 0.047411882484675261), (2, 0.046001356864486448)]
[(0, 0.86302714965184002), (1, 0.070556766093404014), (2, 0.066416084254756008)]
[(0, 0.91210642231730266), (1, 0.043610822378047205), (2, 0.044282755304650076)]
[(0, 0.86744641908125031), (1, 0.069397773162269388), (2, 0.063155807756480248)]
[(0, 0.043375749164465169), (1, 0.90793994717599336), (2, 0.0486843036595416)]
[(0, 0.05044633363796186), (1, 0.20910467380871967), (2, 0.74044899255331853)]
[(0, 0.10394131046804331), (1, 0.56844844364726166), (2, 0.32761024588469495)]
[(0, 0.05616344410959289), (1, 0.88549815864827286), (2, 0.058338397242134278)]
第一个部分是主题-单词的情况,第一个主题,识别出来我猜是化学袭击的情况,第二个识别出来的应该是。。。我保持中立的意见,呜呜,好伤心哦,第三个识别出来的应该是恐怖分子的主题。好吧,这结果,,我也是醉了~
看每篇文章的分类的结果,1–1,2–1,3–1,4–1,5–2,6–3,7–2,8–2,分出的主题是什么鬼~,,与数据集相关性应该很大。
分析TF-IDF作为特征时候的结果:
[(0, u'0.030*"white" + 0.029*"hous" + 0.028*"chemic" + 0.028*"warn"'), (1, u'0.029*"warn" + 0.028*"love" + 0.028*"white" + 0.027*"prepar"'), (2, u'0.035*"declar" + 0.033*"global" + 0.032*"terrorist" + 0.031*"salahuddin"')]
[(0, 0.60280303631598264), (1, 0.23264180833579853), (2, 0.16455515534821896)]
[(0, 0.57184076647381388), (1, 0.260392660280028), (2, 0.16776657324615807)]
[(0, 0.70437217147464493), (1, 0.15341478080028573), (2, 0.14221304772506937)]
[(0, 0.49227310925114359), (1, 0.24206026486565432), (2, 0.26566662588320206)]
[(0, 0.14355241530931395), (1, 0.14326808829206358), (2, 0.71317949639862233)]
[(0, 0.15180196360281939), (1, 0.18008857355122568), (2, 0.66810946284595507)]
[(0, 0.16618324997971065), (1, 0.17202120977997759), (2, 0.66179554024031184)]
[(0, 0.19706906263334936), (1, 0.63159497067591563), (2, 0.17133596669073495)]
这个应该是算比直接词频作为特征的效果要好吧,识别出的三个主题分别是:第一是按理说应该是化学攻击吧,第二个按理说应该是普通生活主题吧,第三个应该是恐怖分子的主题。效果要稍微好那么一点点,好吧,其实从主题的单词角度来看,其实效果真心不太好了,也许是我的数据太小了,当然有这个的原因呀~
继续坚持不懈,没关系的,你可以的,,内心的小人一直不停的给我加油打气。
此处将代码的参数进行调节:
lda_model = models.ldamodel.LdaModel(texts, num_topics=3, id2word=dictionary, passes=20)
测试结果为:
[(0, u'0.104*"love" + 0.060*"life" + 0.060*"sun" + 0.060*"member"'), (1, u'0.083*"prepar" + 0.083*"attack" + 0.083*"chemic" + 0.064*"white"'), (2, u'0.098*"us" + 0.079*"global" + 0.079*"salahuddin" + 0.079*"terrorist"')]
[(0, 0.027977394225595528), (1, 0.94414088371220772), (2, 0.027881722062196825)]
[(0, 0.041935576115165241), (1, 0.91625751139611755), (2, 0.041806912488717263)]
[(0, 0.025845300331770484), (1, 0.94840637487690949), (2, 0.025748324791320096)]
[(0, 0.03371619747230116), (1, 0.86205146046230308), (2, 0.10423234206539569)]
[(0, 0.025883371892911556), (1, 0.02574844612871539), (2, 0.94836818197837303)]
[(0, 0.030570745082050623), (1, 0.030422855916645987), (2, 0.93900639900130334)]
[(0, 0.05587469290842844), (1, 0.055726454693212024), (2, 0.88839885239835947)]
[(0, 0.92572157096933061), (1, 0.037128377481131472), (2, 0.037150051549537738)]
在TF-IDF中的测试结果:我觉得很神奇,为什么都收敛不到最终的结果,这个是可以收敛的嘛?需要在这个地方打一个大大的问号?
单从较短的文本的主题识别而言,在gensim模块中,LSI的表现效果要优于LDA的。
在做的其中,发现问题:对于gensim库的使用,不太明确,确实应该重新回去好好读一遍,在这里感谢一下,翻译了gensim使用的各位大佬,给你们端茶送水。
在做测试的过程中,发现一个问题,就是每次运行都会有不同的运行结果,我不太确定是不是不收敛的问题,在查阅官方资料时,发现,可能这就是一个系统的特性吧,需要用save 和load 函数来保证模型的持久性。所以,好的模型就保存吧·~
LSI的模型测试结果:
**************LSI*************
[(0, u'0.379*"preparations" + 0.379*"attack" + 0.379*"chemical" + 0.309*"potential"'), (1, u'-0.421*"us" + -0.402*"terrorist" + -0.402*"salahuddin" + -0.312*"india"'), (2, u'-0.632*"love" + -0.316*"need" + -0.316*"raise" + -0.316*"life"')]
[(0, 0.65876181227697583), (1, 0.081476913735450227)]
[(0, 0.47791111838303052), (1, 0.061910883552043598)]
[(0, 0.69974581396716673), (1, 0.077626511321183214)]
[(0, 0.55118831491103282), (1, -0.071913390289939941)]
[(0, 0.049382949835345025), (1, -0.68656004823418748)]
[(0, 0.050109243537853169), (1, -0.63339257912137159)]
[(0, 0.054617058841135928), (1, -0.54128519609559911)]
[(2, -1.0000000000000007)]
LSI模型识别出三个主题:第一个主题是化学攻击,第二个主题是恐怖主义,第三个主题是普通生活的话题。
LDA的再次测试结果,,这样总找好的,难道不会过拟合嘛·~担心中
**************LDA*************
[(0, u'0.101*"love" + 0.058*"family" + 0.058*"sun" + 0.058*"life"'), (1, u'0.096*"terrorist" + 0.096*"salahuddin" + 0.088*"us" + 0.068*"global"'), (2, u'0.071*"preparations" + 0.071*"attack" + 0.071*"chemical" + 0.054*"syrian"')]
[(0, 0.083663228178849941), (1, 0.083306516125512264), (2, 0.83303025569563771)]
[(0, 0.10029266702065466), (1, 0.099850794997724576), (2, 0.79985653798162082)]
[(0, 0.080450036750787532), (1, 0.080110865342045284), (2, 0.8394390979071672)]
[(0, 0.091010311845458436), (1, 0.094361937681609179), (2, 0.81462775047293234)]
[(0, 0.079324177164037044), (1, 0.24368223170437681), (2, 0.67699359113158619)]
[(0, 0.084102295616690345), (1, 0.83211795134498212), (2, 0.08377975303832752)]
[(0, 0.1088822395776104), (1, 0.78223763566625715), (2, 0.1088801247561326)]
[(0, 0.81053905780759494), (1, 0.094815306334920385), (2, 0.094645635857484672)]
对于主题识别而言,第一个是普通生活主题的,第二个是恐怖分子的主题,第三个是化学袭击的主题。