当前位置:   article > 正文

LDA主题模型原理解析与python实现_lda python csdn

lda python csdn

本文转自:LDA主题模型原理解析与python实现_wind_blast的博客-CSDN博客 



 

 

 

 python实现:

  1. #-*- coding:utf-8 -*-
  2. import logging
  3. import logging.config
  4. import ConfigParser
  5. import numpy as np
  6. import random
  7. import codecs
  8. import os
  9. from collections import OrderedDict
  10. #获取当前路径
  11. path = os.getcwd()
  12. #导入日志配置文件
  13. logging.config.fileConfig("logging.conf")
  14. #创建日志对象
  15. logger = logging.getLogger()
  16. # loggerInfo = logging.getLogger("TimeInfoLogger")
  17. # Consolelogger = logging.getLogger("ConsoleLogger")
  18. #导入配置文件
  19. conf = ConfigParser.ConfigParser()
  20. conf.read("setting.conf")
  21. #文件路径
  22. trainfile = os.path.join(path,os.path.normpath(conf.get("filepath", "trainfile")))
  23. wordidmapfile = os.path.join(path,os.path.normpath(conf.get("filepath","wordidmapfile")))
  24. thetafile = os.path.join(path,os.path.normpath(conf.get("filepath","thetafile")))
  25. phifile = os.path.join(path,os.path.normpath(conf.get("filepath","phifile")))
  26. paramfile = os.path.join(path,os.path.normpath(conf.get("filepath","paramfile")))
  27. topNfile = os.path.join(path,os.path.normpath(conf.get("filepath","topNfile")))
  28. tassginfile = os.path.join(path,os.path.normpath(conf.get("filepath","tassginfile")))
  29. #模型初始参数
  30. K = int(conf.get("model_args","K"))
  31. alpha = float(conf.get("model_args","alpha"))
  32. beta = float(conf.get("model_args","beta"))
  33. iter_times = int(conf.get("model_args","iter_times"))
  34. top_words_num = int(conf.get("model_args","top_words_num"))
  35. class Document(object):
  36. def __init__(self):
  37. self.words = []
  38. self.length = 0
  39. #把整个文档及真的单词构成vocabulary(不允许重复)
  40. class DataPreProcessing(object):
  41. def __init__(self):
  42. self.docs_count = 0
  43. self.words_count = 0
  44. #保存每个文档d的信息(单词序列,以及length)
  45. self.docs = []
  46. #建立vocabulary表,照片文档的单词
  47. self.word2id = OrderedDict()
  48. def cachewordidmap(self):
  49. with codecs.open(wordidmapfile, 'w','utf-8') as f:
  50. for word,id in self.word2id.items():
  51. f.write(word +"\t"+str(id)+"\n")
  52. class LDAModel(object):
  53. def __init__(self,dpre):
  54. self.dpre = dpre #获取预处理参数
  55. #
  56. #模型参数
  57. #聚类个数K,迭代次数iter_times,每个类特征词个数top_words_num,超参数α(alpha) β(beta)
  58. #
  59. self.K = K
  60. self.beta = beta
  61. self.alpha = alpha
  62. self.iter_times = iter_times
  63. self.top_words_num = top_words_num
  64. #
  65. #文件变量
  66. #分好词的文件trainfile
  67. #词对应id文件wordidmapfile
  68. #文章-主题分布文件thetafile
  69. #词-主题分布文件phifile
  70. #每个主题topN词文件topNfile
  71. #最后分派结果文件tassginfile
  72. #模型训练选择的参数文件paramfile
  73. #
  74. self.wordidmapfile = wordidmapfile
  75. self.trainfile = trainfile
  76. self.thetafile = thetafile
  77. self.phifile = phifile
  78. self.topNfile = topNfile
  79. self.tassginfile = tassginfile
  80. self.paramfile = paramfile
  81. # p,概率向量 double类型,存储采样的临时变量
  82. # nw,词word在主题topic上的分布
  83. # nwsum,每各topic的词的总数
  84. # nd,每个doc中各个topic的词的总数
  85. # ndsum,每各doc中词的总数
  86. self.p = np.zeros(self.K)
  87. # nw,词word在主题topic上的分布
  88. self.nw = np.zeros((self.dpre.words_count,self.K),dtype="int")
  89. # nwsum,每各topic的词的总数
  90. self.nwsum = np.zeros(self.K,dtype="int")
  91. # nd,每个doc中各个topic的词的总数
  92. self.nd = np.zeros((self.dpre.docs_count,self.K),dtype="int")
  93. # ndsum,每各doc中词的总数
  94. self.ndsum = np.zeros(dpre.docs_count,dtype="int")
  95. self.Z = np.array([ [0 for y in xrange(dpre.docs[x].length)] for x in xrange(dpre.docs_count)]) # M*doc.size(),文档中词的主题分布
  96. #随机先分配类型,为每个文档中的各个单词分配主题
  97. for x in xrange(len(self.Z)):
  98. self.ndsum[x] = self.dpre.docs[x].length
  99. for y in xrange(self.dpre.docs[x].length):
  100. topic = random.randint(0,self.K-1)#随机取一个主题
  101. self.Z[x][y] = topic#文档中词的主题分布
  102. self.nw[self.dpre.docs[x].words[y]][topic] += 1
  103. self.nd[x][topic] += 1
  104. self.nwsum[topic] += 1
  105. self.theta = np.array([ [0.0 for y in xrange(self.K)] for x in xrange(self.dpre.docs_count) ])
  106. self.phi = np.array([ [ 0.0 for y in xrange(self.dpre.words_count) ] for x in xrange(self.K)])
  107. def sampling(self,i,j):
  108. #换主题
  109. topic = self.Z[i][j]
  110. #只是单词的编号,都是从0开始word就是等于j
  111. word = self.dpre.docs[i].words[j]
  112. #if word==j:
  113. # print 'true'
  114. self.nw[word][topic] -= 1
  115. self.nd[i][topic] -= 1
  116. self.nwsum[topic] -= 1
  117. self.ndsum[i] -= 1
  118. Vbeta = self.dpre.words_count * self.beta
  119. Kalpha = self.K * self.alpha
  120. self.p = (self.nw[word] + self.beta)/(self.nwsum + Vbeta) * \
  121. (self.nd[i] + self.alpha) / (self.ndsum[i] + Kalpha)
  122. #随机更新主题的吗
  123. # for k in xrange(1,self.K):
  124. # self.p[k] += self.p[k-1]
  125. # u = random.uniform(0,self.p[self.K-1])
  126. # for topic in xrange(self.K):
  127. # if self.p[topic]>u:
  128. # break
  129. #按这个更新主题更好理解,这个效果还不错
  130. p = np.squeeze(np.asarray(self.p/np.sum(self.p)))
  131. topic = np.argmax(np.random.multinomial(1, p))
  132. self.nw[word][topic] +=1
  133. self.nwsum[topic] +=1
  134. self.nd[i][topic] +=1
  135. self.ndsum[i] +=1
  136. return topic
  137. def est(self):
  138. # Consolelogger.info(u"迭代次数为%s 次" % self.iter_times)
  139. for x in xrange(self.iter_times):
  140. for i in xrange(self.dpre.docs_count):
  141. for j in xrange(self.dpre.docs[i].length):
  142. topic = self.sampling(i,j)
  143. self.Z[i][j] = topic
  144. logger.info(u"迭代完成。")
  145. logger.debug(u"计算文章-主题分布")
  146. self._theta()
  147. logger.debug(u"计算词-主题分布")
  148. self._phi()
  149. logger.debug(u"保存模型")
  150. self.save()
  151. def _theta(self):
  152. for i in xrange(self.dpre.docs_count):#遍历文档的个数词
  153. self.theta[i] = (self.nd[i]+self.alpha)/(self.ndsum[i]+self.K * self.alpha)
  154. def _phi(self):
  155. for i in xrange(self.K):
  156. self.phi[i] = (self.nw.T[i] + self.beta)/(self.nwsum[i]+self.dpre.words_count * self.beta)
  157. def save(self):
  158. # 保存theta文章-主题分布
  159. logger.info(u"文章-主题分布已保存到%s" % self.thetafile)
  160. with codecs.open(self.thetafile,'w') as f:
  161. for x in xrange(self.dpre.docs_count):
  162. for y in xrange(self.K):
  163. f.write(str(self.theta[x][y]) + '\t')
  164. f.write('\n')
  165. # 保存phi词-主题分布
  166. logger.info(u"词-主题分布已保存到%s" % self.phifile)
  167. with codecs.open(self.phifile,'w') as f:
  168. for x in xrange(self.K):
  169. for y in xrange(self.dpre.words_count):
  170. f.write(str(self.phi[x][y]) + '\t')
  171. f.write('\n')
  172. # 保存参数设置
  173. logger.info(u"参数设置已保存到%s" % self.paramfile)
  174. with codecs.open(self.paramfile,'w','utf-8') as f:
  175. f.write('K=' + str(self.K) + '\n')
  176. f.write('alpha=' + str(self.alpha) + '\n')
  177. f.write('beta=' + str(self.beta) + '\n')
  178. f.write(u'迭代次数 iter_times=' + str(self.iter_times) + '\n')
  179. f.write(u'每个类的高频词显示个数 top_words_num=' + str(self.top_words_num) + '\n')
  180. # 保存每个主题topic的词
  181. logger.info(u"主题topN词已保存到%s" % self.topNfile)
  182. with codecs.open(self.topNfile,'w','utf-8') as f:
  183. self.top_words_num = min(self.top_words_num,self.dpre.words_count)
  184. for x in xrange(self.K):
  185. f.write(u'第' + str(x) + u'类:' + '\n')
  186. twords = []
  187. twords = [(n,self.phi[x][n]) for n in xrange(self.dpre.words_count)]
  188. twords.sort(key = lambda i:i[1], reverse= True)
  189. for y in xrange(self.top_words_num):
  190. word = OrderedDict({value:key for key, value in self.dpre.word2id.items()})[twords[y][0]]
  191. f.write('\t'*2+ word +'\t' + str(twords[y][1])+ '\n')
  192. # 保存最后退出时,文章的词分派的主题的结果
  193. logger.info(u"文章-词-主题分派结果已保存到%s" % self.tassginfile)
  194. with codecs.open(self.tassginfile,'w') as f:
  195. for x in xrange(self.dpre.docs_count):
  196. for y in xrange(self.dpre.docs[x].length):
  197. f.write(str(self.dpre.docs[x].words[y])+':'+str(self.Z[x][y])+ '\t')
  198. f.write('\n')
  199. logger.info(u"模型训练完成。")
  200. # 数据预处理,即:生成d()单词序列,以及词汇表
  201. def preprocessing():
  202. logger.info(u'载入数据......')
  203. with codecs.open(trainfile, 'r','utf-8') as f:
  204. docs = f.readlines()
  205. logger.debug(u"载入完成,准备生成字典对象和统计文本数据...")
  206. # 大的文档集
  207. dpre = DataPreProcessing()
  208. items_idx = 0
  209. for line in docs:
  210. if line != "":
  211. tmp = line.strip().split()
  212. # 生成一个文档对象:包含单词序列(w1,w2,w3,,,,,wn)可以重复的
  213. doc = Document()
  214. for item in tmp:
  215. if dpre.word2id.has_key(item):# 已有的话,只是当前文档追加
  216. doc.words.append(dpre.word2id[item])
  217. else: # 没有的话,要更新vocabulary中的单词词典及wordidmap
  218. dpre.word2id[item] = items_idx
  219. doc.words.append(items_idx)
  220. items_idx += 1
  221. doc.length = len(tmp)
  222. dpre.docs.append(doc)
  223. else:
  224. pass
  225. dpre.docs_count = len(dpre.docs) # 文档数
  226. dpre.words_count = len(dpre.word2id) # 词汇数
  227. logger.info(u"共有%s个文档" % dpre.docs_count)
  228. dpre.cachewordidmap()
  229. logger.info(u"词与序号对应关系已保存到%s" % wordidmapfile)
  230. return dpre
  231. def run():
  232. # 处理文档集,及计算文档数,以及vocabulary词的总个数,以及每个文档的单词序列
  233. dpre = preprocessing()
  234. lda = LDAModel(dpre)
  235. lda.est()
  236. if __name__ == '__main__':
  237. run()

 

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/358837
推荐阅读
相关标签
  

闽ICP备14008679号