本文参考理论知识:http://blog.csdn.net/huagong_adu/article/details/7937616
主题模型是对文档中隐含的主题进行建模,考虑了上下文语义之间的关系。
一个主题就好像一个“桶”,它装了若干出现概率较高的词语。这些词语和这个主题有很强的相关性,
或者说,正是这些词语共同定义了这个主题。对于一段话来说,有些词语可以出自这个“桶”,有些
可能来自那个“桶”,一段文本往往是若干个主题的杂合体。相当于软聚类,适用于长文本
主题模型分为两大类:PLSA模型和LDA模型,
一.pLSA主要使用的是EM(期望最大化)算法,类似SVD分解主题相当于隐含特征
二.LDA采用的是Gibbs sampling方法和狄利克雷分布。通过文档-->主题-->单词构建模型
具体过程如下
LDA的三个表示层被三种颜色表示出来:
α:分布p(θ)需要一个向量参数,即Dirichlet分布的参数,用于生成一个主题θ向量;
β:各个主题对应的单词概率分布矩阵p(w|z)。
1. corpus-level(红色):α和β表示语料级别的参数,也就是每个文档都一样,因此生成过程只采样一次。
2.document-level(橙色):θ是文档级别的变量,每个文档对应一个θ,也就是每个文档产生各个主题z的概率是不同的,所有生成每个文档采样一次θ。
3. word-level(绿色):z和w都是单词级别变量,z由θ生成,w由z和β共同生成,一个 单词w对应一个主题z。
通过上面对LDA生成模型的讨论,可以知道LDA模型主要是从给定的输入语料中学习训练两个控制参数α和β,学习出了这两个控制参数就确定了模型,便可以用来生成文档。其中α和β分别对应以下各个信息:
把w当做观察变量,θ和z当做隐藏变量,就可以通过EM算法学习出α和β,求解过程中遇到后验概率p(θ,z|w)无法直接求解,需要找一个似然函数下界来近似求解,原文使用基于分解(factorization)假设的变分法(varialtional inference)进行计算,用到了EM算法。每次E-step输入α和β,计算似然函数,M-step最大化这个似然函数,算出α和β,不断迭代直到收敛。
TF-IDF用以评估一字词对于一个文件集或一个语料库中的其中一份文件的重要程度。字词的重要性随着它在文件中出现的次数成正比增加,但同时会随着它在语料库中出现的频率成反比下降。TF-IDF加权的各种形式常被搜索引擎应用,作为文件与用户查询之间相关程度的度量或评级。
tf:词频,指的是某一个给定的词语在该文件中出现的频率
idf:倒文档词频,是一个词语普遍重要性的度量。某一特定词语的IDF,可以由总文件数目除以包含该词语之文件的数目,再将得到的商取对数得到
def predict_data(): jieba.load_userdict('stopword.txt') #增加自定义词典,结巴里的词典不能满足你的需求 df = pd.read_csv('bad_cmmnt_detl.csv') #读数据, def cutword(x): seg = jieba.cut(x) #结巴分词函数 return ' '.join(seg)# df['seg_word']=df.GOOD_CNTNT.apply(cutword) #文档词向量,必须转成列表, txt = df.seg_word.values txtlist = [] for sent in txt: temp = [w for w in sent.split()] txtlist.append(temp) return df, txtlist def stopwords(): stop = pd.read_csv('stopwords.txt', encoding = 'utf-8', header = None, sep = 'tipdm') stop = [' ', ''] + list(stop[0]) #Pandas自动过滤了空格符,这里手动添加 return stop def Lsimodel(txtlist): dic = corpora.Dictionary(txtlist) #可以理解为python中的字典对象, 其Key是字典中的词,其Val是词对应的唯一数值型ID ,#由doc2bow变为词袋,词袋模型, #print (dic.token2id),词和次出现次数 corpus = [dic.doc2bow(text) for text in txtlist ] ##用字符表示的文档转化成用ID表示的文档向量 tfidf = models.TfidfModel(corpus) #使用tf-idf 模型得出该评论集的tf-idf 模型 corpus_tfidf = tfidf[corpus] ##基于这个TF-IDF模型,我们可以将上述用词频表示文档向量表示为一个用tf-idf值表示的文档向量: lsi = models.LsiModel(corpus_tfidf, id2word=dic, num_topics=10) print ('原始lsi') print (lsi.print_topics(4)) def corpus_stop_words(df,txtlist,stop): df['seg_word1'] = df.seg_word.apply(lambda s: s.split(' ')) df.head() df['seg_word2'] = df.seg_word1.apply(lambda x: [i for i in x if i not in stop]) #逐词判断是否停用词,思路同上 txt2 = df.seg_word2.values dic = corpora.Dictionary(txt2) corpus = [dic.doc2bow(text) for text in txt2 ] tfidf = models.TfidfModel(corpus) corpus_tfidf = tfidf[corpus] return corpus_tfidf,dic def LSA_model(corpus_tfidf,dic): lsi = models.LsiModel(corpus_tfidf, id2word=dic, num_topics=10) print ('过滤停止词的LSI') print (lsi.print_topics(5)) def LDAmodel(corpus_tfidf,dic): lda = models.LdaModel(corpus_tfidf, id2word=dic, num_topics=10) print ('过滤停止词的LAD') print (lda.print_topics(5)) if __name__=='__main__': df, txtlist= predict_data() stop = stopwords() Lsimodel(txtlist) corpus_tfidf,dic = corpus_stop_words(df,txtlist,stop) LSA_model(corpus_tfidf,dic) LDAmodel(corpus_tfidf,dic)
模型输出结果如下所示,原始的LSI有太多标点符号,效果较差,看不出每个主题的大致含义
[(0, '0.382*"!" + 0.243*"," + 0.225*"。" + 0.222*"的" + 0.204*"了" + 0.168*"不" + 0.165*"是" + 0.159*"买" + 0.158*"都" + 0.146*"我"'),
(1, '-0.891*"!" + 0.254*"。" + 0.125*"," + 0.092*"的" + 0.089*"不" + 0.070*"了" + 0.070*"是" + 0.068*"不好" + 0.068*"买" + 0.060*"都"'),
(2, '0.691*"不好" + 0.270*"用" + -0.261*"?" + 0.226*"差" + 0.210*"质量" + 0.138*"一点" + -0.122*"我" + 0.118*"太" + -0.115*"月" + 0.106*"很"'),
(3, '-0.513*"过期" + -0.359*"月" + -0.275*"快" + 0.225*"?" + -0.218*"年" + -0.194*"日期" + -0.161*"。" + -0.151*"保质期" + -0.147*"新鲜" + 0.144*"没有"')]
过滤停止词的LSI可以大致看到每一个主题的含义,如第一个主题质量不好、过期何第二主题类似
[(0, '-0.323*"买" + -0.271*"不好" + -0.246*"差" + -0.240*"过期" + -0.227*"差评" + -0.204*"东西" + -0.202*"太" + -0.160*"质量" + -0.150*"收到" + -0.142*"坏"'),
(1, '-0.891*"不好" + 0.181*"过期" + 0.150*"差评" + -0.150*"质量" + -0.124*"一点" + 0.113*"收到" + 0.103*"买" + 0.075*"货" + 0.068*"东西" + 0.064*"一号店"'),
(2, '0.757*"过期" + -0.346*"差" + 0.192*"不好" + 0.177*"日期" + -0.173*"太" + -0.163*"质量" + 0.110*"牛奶" + 0.109*"新鲜" + 0.108*"保质期" + -0.105*"坏"'),
(3, '0.535*"差" + -0.448*"差评" + 0.316*"过期" + 0.311*"太" + 0.235*"难吃" + -0.198*"收到" + 0.197*"质量" + -0.155*"不好" + -0.109*"货" + -0.102*"\n"'),
(4, '0.512*"难吃" + -0.411*"差" + 0.341*"味道" + -0.292*"差评" + 0.266*"好吃" + 0.232*"买" + -0.171*"质量" + 0.159*"吃" + -0.142*"过期" + 0.108*"假"'),
(5, '-0.736*"差评" + -0.391*"难吃" + 0.307*"收到" + 0.218*"货" + 0.131*"买" + 0.108*"坏" + -0.093*"好吃" + 0.090*"东西" + -0.086*"差" + -0.081*"味道"'),
(6, '-0.567*"难吃" + 0.345*"味道" + -0.336*"收到" + -0.274*"货" + 0.260*"买" + 0.233*"坏" + -0.188*"\n" + 0.125*"假" + 0.120*"假货" + -0.119*"不好"'),
(7, '0.871*"坏" + -0.267*"味道" + 0.122*"难吃" + -0.111*"假货" + -0.108*"买" + 0.105*"新鲜" + -0.097*"假" + 0.073*"\n" + -0.071*"感觉" + -0.067*"货"'),
(8, '0.582*"新鲜" + 0.524*"日期" + -0.288*"垃圾" + -0.237*"过期" + 0.149*"好吃" + -0.146*"东西" + 0.120*"收到" + 0.117*"货" + 0.110*"差评" + -0.108*"难吃"'),
(9, '0.478*"味道" + 0.444*"收到" + 0.326*"货" + -0.298*"垃圾" + -0.239*"新鲜" + -0.238*"买" + -0.216*"日期" + 0.187*"过期" + 0.145*"坏" + -0.125*"快递"')]
过滤停止词的LAD比LSI模型效果要好,第一个主题主要是质量不好、口感差,第二个主题主要是用户主管感受难吃、问道不好闻、东西比较薄等
[(0, '0.013*"差" + 0.007*"太" + 0.007*"质量" + 0.005*"买" + 0.005*"好吃" + 0.005*"很差" + 0.005*"东西" + 0.004*"口感" + 0.004*"特别" + 0.004*"一点"'),
(1, '0.011*"难吃" + 0.008*"买" + 0.007*"味道" + 0.007*"货" + 0.006*"收到" + 0.005*"薄" + 0.005*"便宜" + 0.004*"塑料瓶" + 0.004*"太" + 0.004*"真心"'),
(2, '0.011*"日期" + 0.009*"新鲜" + 0.007*"太小" + 0.006*"喝" + 0.005*"满意" + 0.005*"难看" + 0.005*"买" + 0.004*"痒" + 0.004*"不好" + 0.003*"难"'),
(3, '0.012*"过期" + 0.005*"买" + 0.005*"东西" + 0.004*"千万别" + 0.004*"一包" + 0.004*"差评" + 0.004*"客服" + 0.004*"\n" + 0.003*"商家" + 0.003*"上当"'),
(4, '0.008*"差评" + 0.006*"买" + 0.005*"效果" + 0.005*"假" + 0.005*"到期" + 0.005*"袋子" + 0.004*"结块" + 0.004*"感觉" + 0.004*"油" + 0.004*"差差"'),
(5, '0.013*"不好" + 0.008*"快递" + 0.007*"太慢" + 0.007*"慢" + 0.007*"物流" + 0.007*"收到" + 0.006*"送" + 0.006*"东西" + 0.006*"漏出来" + 0.006*"差评"'),
(6, '0.010*"垃圾" + 0.009*"碎" + 0.006*"吃" + 0.006*"客服" + 0.006*"生产日期" + 0.006*"买" + 0.005*"东西" + 0.005*"过期" + 0.004*"漏" + 0.004*"满意"'),
(7, '0.007*"坏" + 0.006*"买" + 0.005*"\n" + 0.005*"保质期" + 0.005*"一瓶" + 0.005*"满意" + 0.004*"包装" + 0.004*"打包" + 0.004*"临近" + 0.004*"东西"'),
(8, '0.006*"假货" + 0.005*"鸡蛋" + 0.005*"买" + 0.005*"货物" + 0.004*"送过来" + 0.004*"差" + 0.003*"很小" + 0.003*"噪音" + 0.003*"客服" + 0.003*"收到"'),
(9, '0.008*"发票" + 0.008*"没收" + 0.006*"买" + 0.005*"越来越" + 0.005*"元" + 0.005*"卖" + 0.004*"1号店" + 0.004*"到货" + 0.004*"赠品" + 0.004*"苹果"')]
后续可以通过优化样本,优化词库提高LDA的效果,