Python探索之pLSA实现代码


Posted in Python onOctober 25, 2017

pLSA(probabilistic Latent Semantic Analysis),概率潜在语义分析模型,是1999年Hoffman提出的一个被称为第一个能解决一词多义问题的模型,通过在文档与单词之间建立一层主题(Topic),将文档与单词的直接关联转化为文档与主题的关联以及主题与单词的关联。这里采用EM算法进行估计,可能存在差错,望积极批评指正。

# -*- coding: utf-8 -*-
import math
import random
import jieba
import codecs
import datetime

class pLSA_lph():
  def __init__(self, ntopic = 5):
    self.n_doc = 0
    self.n_word = 0
    self.n_topic = ntopic
    self.corpus = None
    self.p_z_dw = None
    self.p_w_z = None
    self.p_z_d = None
    self.likelihood = 0
    self.vocab = None
    self.stop_words = [u',', u'。', u'、', u'(', u')', u'·', u'!', u' ', u':', u'“', u'”', u'\n']
  # 每行和为1的正实数,概率分布;
  def _rand_mat(self, sizex, sizey):
    ret = []
    for i in xrange(sizex):
      ret.append([])
      for _ in xrange(sizey):
        ret[-1].append(random.random())
      norm = sum(ret[-1])
      for j in xrange(sizey):
        ret[-1][j] /= norm
    return ret
  #从文本中计算词频稀疏矩阵,这里存储模型仿照LDA
  def loadCorpus(self, fn):
    # 中文分词
    f = open(fn, 'r')
    text = f.readlines()
    text = r' '.join(text)
    seg_generator = jieba.cut(text)
    seg_list = [i for i in seg_generator if i not in self.stop_words]
    seg_list = r' '.join(seg_list)
    # 切割统计所有出现的词纳入词典
    seglist = seg_list.split(" ")
    self.vocab = []
    for word in seglist:
      if (word != u' ' and word not in self.vocab):
        self.vocab.append(word)
    self.n_word =len(self.vocab)
    CountMatrix = []
    f.seek(0, 0)
    # 统计每个文档中出现的词频
    for line in f:
      # 置零
      count = [0 for i in range(len(self.vocab))]
      text = line.strip()
      # 但还是要先分词
      seg_generator = jieba.cut(text)
      seg_list = [i for i in seg_generator if i not in self.stop_words]
      seg_list = r' '.join(seg_list)
      seglist = seg_list.split(" ")
      # 查询词典中的词出现的词频
      for word in seglist:
        if word in self.vocab:
          count[self.vocab.index(word)] += 1
      CountMatrix.append(count)
    f.close()
    self.corpus = CountMatrix
    self.n_doc = len(CountMatrix)
    #初始化
    self.p_z_d = self._rand_mat(self.n_topic, self.n_doc)
    self.p_w_z = self._rand_mat(self.n_word, self.n_topic)
    self.p_z_dw =[]
    for k in range(self.n_topic):
      self.p_z_dw.append(self._rand_mat(self.n_doc, self.n_word))

  def _e_step(self):
    for k in range(self.n_topic):
      for d in range(self.n_doc):
        for j in range(self.n_word):
          _d_wz_zd = 0
          for kk in range(self.n_topic):
            _d_wz_zd += self.p_w_z[j][kk]*self.p_z_d[kk][d]
          if _d_wz_zd <= 0:
            _d_wz_zd = 1e-6
          self.p_z_dw[k][d][j] = self.p_w_z[j][k]*self.p_z_d[k][d]/_d_wz_zd
  def _m_step(self):
    print "updating Pn(Wj|Zk)...\r"
    for j in range(self.n_word):
      for k in range(self.n_topic):
        _d_dw_zdw = 0
        for d in range(self.n_doc):
          _d_dw_zdw += self.corpus[d][j]*self.p_z_dw[k][d][j]
        _d_dw_zdw_sum = 0
        for jj in range(self.n_word):
          _d_dw_zdw_i = 0
          for d in range(self.n_doc):
            _d_dw_zdw_i += self.corpus[d][jj]*self.p_z_dw[k][d][jj]
          _d_dw_zdw_sum += _d_dw_zdw_i
        if _d_dw_zdw_sum <= 0:
          _d_dw_zdw_sum = 1e-6
        self.p_w_z[j][k] = _d_dw_zdw/_d_dw_zdw_sum
    print "updating Pn(Zk|Di)...\r"
    for k in range(self.n_topic):
      for d in range(self.n_doc):
        _d_dw_zdw = 0
        for j in range(self.n_word):
          _d_dw_zdw += self.corpus[d][j]*self.p_z_dw[k][d][j]
        _d_dw_zdw_sum = 0
        for kk in range(self.n_topic):
          _d_dw_zdw_i = 0
          for j in range(self.n_word):
            _d_dw_zdw_i += self.corpus[d][j]*self.p_z_dw[kk][d][j]
          _d_dw_zdw_sum += _d_dw_zdw_i
        if _d_dw_zdw_sum <= 0:
          _d_dw_zdw_sum = 1e-6
        self.p_z_d[k][d] = _d_dw_zdw/_d_dw_zdw_sum
  #计算最大似然值
  def _cal_max_likelihood(self):
    self.likelihood = 0
    for d in range(self.n_doc):
      for j in range(self.n_word):
        _dP_wjdi = 0
        for k in range(self.n_topic):
          _dP_wjdi += self.p_w_z[j][k]*self.p_z_d[k][d]
        _dP_wjdi = 1.0/self.n_doc*_dP_wjdi
        self.likelihood += self.corpus[d][j]*math.log(_dP_wjdi)
  #迭代训练
  def train(self, n_iter = 100, d_delta = 1e-6,log_fn = "log.log"):
    itr = 0
    delta =10e9
    _likelihood = 0
    f = open(log_fn, 'w')
    while itr < n_iter and delta > d_delta:
      _likelihood = self.likelihood
      self._e_step()
      self._m_step()
      self._cal_max_likelihood()
      itr += 1
      delta = abs(self.likelihood - _likelihood)
      t1 = datetime.datetime.now().strftime('%Y-%m-%d-%y %H:%M:%S');
      f.write("%s iteration %d, max-likelihood = %.6f\n"%(t1, itr, self.likelihood))
      print "%s iteration %d, max-likelihood = %.6f"%(t1, itr, self.likelihood)
    f.close()

  def printVocabulary(self):
    print "vocabulary:"
    for word in self.vocab:
      print word,
    print
  def saveVocabulary(self, fn):
    f = codecs.open(fn, 'w', 'utf-8')
    for word in self.vocab:
      f.write("%s\n"%word)
    f.close()
  def printWordOfTopic(self):
    for k in range(self.n_topic):
      print "Topic %d"%k,
      for j in range(self.n_word):
        print self.p_w_z[j][k],
      print
  def saveWordOfTopic(self,fn):
    f = open(fn, 'w')
    for j in range(self.n_word):
      f.write(", w%d"%j)
    f.write("\n")
    for k in range(self.n_topic):
      f.write("topic %d"%k)
      for j in range(self.n_word):
        f.write(", %.6f"%self.p_w_z[j][k])
      f.write("\n")
    f.close()
  def printTopicOfDoc(self):
    for d in range(self.n_doc):
      print "Doc %d"%d,
      for k in range(self.n_topic):
        print self.p_z_d[k][d],
      print
  def saveTopicOfDoc(self, fn):
    f = open(fn, 'w')
    for k in range(self.n_topic):
      f.write(", z%d" % k)
    f.write("\n")
    for d in range(self.n_doc):
      f.write("doc %d" % d)
      for k in range(self.n_topic):
        f.write(", %.6f" % self.p_z_d[k][d])
      f.write("\n")
    f.close()

依旧采用上一篇文章中的两个政治新闻作为语料库:

<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">新华社北京11月26日电中共中央总书记、国家主席习近平26日向古巴共产党中央委员会第一书记、国务委员会主席兼部长会议主席劳尔·卡斯特罗致唁电,代表中国党、政府、人民并以个人名义,对菲德尔·卡斯特罗同志逝世表示最沉痛的哀悼,向其家属致以最诚挚的慰问。全文如下:惊悉古巴革命领导人菲德尔·卡斯特罗同志不幸逝世,我谨代表中国共产党、政府、人民,并以我个人的名义,向你并通过你向古巴共产党、政府、人民,对菲德尔·卡斯特罗同志的逝世表示最沉痛的哀悼,向其家属致以最诚挚的慰问。菲德尔·卡斯特罗同志是古巴共产党和古巴社会主义事业的缔造者,是古巴人民的伟大领袖。他把毕生精力献给了古巴人民争取民族解放、维护国家主权、建设社会主义的壮丽事业,为古巴人民建立了不朽的历史功勋,也为世界社会主义发展建立了不朽的历史功勋。菲德尔·卡斯特罗同志是我们这个时代的伟大人物,历史和人民将记住他。我多次同菲德尔·卡斯特罗同志见面,促膝畅谈,他的真知灼见令我深受启发,他的音容笑貌犹在眼前。我深深怀念他,中国人民深深怀念他。菲德尔·卡斯特罗同志生前致力于中古友好,密切关注和高度评价中国发展进程,在他亲自关心和支持下,古巴成为第一个同新中国建交的拉美国家。建交56年来,中古关系长足发展,各领域务实合作成果丰硕,两国人民友谊与日俱增,这都与菲德尔·卡斯特罗同志的关怀和心血密不可分。菲德尔·卡斯特罗同志的逝世是古巴和拉美人民的重大损失,不仅使古巴和拉美人民失去了一位优秀儿子,也使中国人民失去了一位亲密的同志和真诚的朋友。他的光辉形象和伟大业绩将永载史册。我相信,在主席同志坚强领导下,古巴党、政府、人民必将继承菲德尔·卡斯特罗同志的遗志,化悲痛为力量,在社会主义建设事业中不断取得新的成绩。中古两党、两国、两国人民友谊必将得到巩固和发展。伟大的菲德尔·卡斯特罗同志永垂不朽!(完)</span>

据韩联社报道,当地时间29日下午2时30分,韩国总统朴槿惠发表“亲信门”事件后的第3次对国民谈话。据报道,朴槿惠在谈话中表示,“我没有管理好周围的人,导致出现了一些失误。这次事件的过程将尽快向大家说明具体情况。”朴槿惠表示,之前因考虑到国内外各种困难,为了国家和人民,如何才是正确的选择,每晚都辗转反侧,难以入睡。朴槿惠指出,将把总统任期相关问题交给国会和朝野两党决定,将遵守相应规定,辞去总统职务,放下一切。朴槿惠表示,希望韩国尽快摆脱混乱局面,步入正轨。并再次向国民衷心表示道歉。希望两党能尽快齐心协力,解决当前局面,此前,在“亲信门”事件曝光后,朴槿惠曾分别于10月25日和11月4日两次发表讲话,向民众表示歉意。10月25日在青瓦台发表对国民谈话时,朴槿惠承认大选时及就任总统后曾就部分资料征求过亲信崔顺实意见,并就此事向全体国民道歉。11月4日上午,朴槿惠在青瓦台召开记者招待会,就亲信干政事件发表第二次对国民讲话, 称愿意接受特别检察组的调查。韩联社称,依据宪法享有刑事检控豁免特权的在任总统表明接受检方调查的立场,为韩国68年宪政史所仅见。

主函数入口:

if __name__=="__main__":

  _plsa = pLSA_lph(2)
  _plsa.loadCorpus(u"C:\\Users\Administrator\Desktop\\zhongwen.txt")
  _plsa.train()
  _plsa.printTopicOfDoc()
  _plsa.printWordOfTopic()
  _plsa.saveTopicOfDoc(u"C:\\Users\Administrator\Desktop\\topic_doc.txt")
  _plsa.saveWordOfTopic(u"C:\\Users\Administrator\Desktop\\word_topic.txt")

输出每个文档中的主题分布如下:

Doc 0 0.999999999627 3.72945076781e-10
Doc 1 3.52196229806e-11 0.999999999965

总结

以上就是本文关于Python探索之pLSA实现代码的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站:python正则表达式re之compile函数解析、python+mongodb数据抓取详细介绍、Python_LDA实现方法详解等,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!

Python 相关文章推荐
python求素数示例分享
Feb 16 Python
python WindowsError的错误代码详解
Jul 23 Python
python获取外网IP并发邮件的实现方法
Oct 01 Python
对python的文件内注释 help注释方法
May 23 Python
python绘制直线的方法
Jun 30 Python
python交换两个变量的值方法
Jan 12 Python
wxpython布局的实现方法
Nov 01 Python
python反转列表的三种方式解析
Nov 08 Python
Python中文分词库jieba,pkusegwg性能准确度比较
Feb 11 Python
使用Tensorboard工具查看Loss损失率
Feb 15 Python
python中random模块详解
Mar 01 Python
Python+Pillow+Pytesseract实现验证码识别
May 11 Python
python正则表达式re之compile函数解析
Oct 25 #Python
Python2和Python3中print的用法示例总结
Oct 25 #Python
Python_LDA实现方法详解
Oct 25 #Python
python+mongodb数据抓取详细介绍
Oct 25 #Python
python装饰器实例大详解
Oct 25 #Python
Python3 模块、包调用&amp;路径详解
Oct 25 #Python
Python探索之创建二叉树
Oct 25 #Python
You might like
第十二节--类的自动加载
2006/11/16 PHP
php adodb连接带密码access数据库实例,测试成功
2008/05/14 PHP
用sql命令修改数据表中的一个字段为非空(not null)的语句
2010/06/04 PHP
linux命令之调试工具strace的深入分析
2013/06/03 PHP
php使用pack处理二进制文件的方法
2014/07/03 PHP
windows7下安装php的imagick和imagemagick扩展教程
2014/07/04 PHP
新浪微博OAuth认证和储存的主要过程详解
2015/03/27 PHP
setTimeout 不断吐食CPU的问题分析
2009/04/01 Javascript
基于jQuery UI CSS Framework开发Widget的经验
2010/08/21 Javascript
用javascript作一个通用向导说明
2011/08/30 Javascript
JavaScript检测并限制复选框选中个数的方法
2015/08/12 Javascript
js 求时间差的实现代码
2016/04/26 Javascript
全面介绍javascript实用技巧及单竖杠
2016/07/18 Javascript
JS简单实现禁止访问某个页面的方法
2016/09/13 Javascript
基于Vue2.0的分页组件
2017/03/16 Javascript
JavaScript中undefined和null的区别
2017/05/03 Javascript
详解AngularJs路由之Ui-router-resolve(预加载)
2017/06/13 Javascript
微信小程序使用swiper组件实现类3D轮播图
2018/08/29 Javascript
JavaScript原型式继承实现方法
2019/11/06 Javascript
Vue中的this.$options.data()和this.$data用法说明
2020/07/26 Javascript
Nuxt.js的路由跳转操作(页面跳转nuxt-link)
2020/11/06 Javascript
解决pyttsx3无法封装的问题
2018/12/24 Python
浅谈Python爬虫基本套路
2019/03/25 Python
详解Python连接MySQL数据库的多种方式
2019/04/16 Python
Python 硬币兑换问题
2019/07/29 Python
python如果快速判断数字奇数偶数
2019/11/13 Python
Python算法的时间复杂度和空间复杂度(实例解析)
2019/11/19 Python
Python GUI自动化实现绕过验证码登录
2020/01/10 Python
HTML5中input[type='date']自定义样式与日历校验功能的实现代码
2017/07/11 HTML / CSS
化工工艺专业求职信
2013/09/22 职场文书
企划经理的岗位职责
2013/11/17 职场文书
新郎父亲婚宴答谢词
2014/01/11 职场文书
户籍证明模板
2014/09/28 职场文书
党委书记个人检查对照材料思想汇报
2014/10/11 职场文书
2015年超市员工工作总结
2015/05/04 职场文书
css3实现背景图片半透明内容不透明的方法示例
2021/04/13 HTML / CSS