Python探索之pLSA实现代码

作者:liuph_ 时间:2022-01-03 11:30:28 

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

来源:http://blog.csdn.net/liuph_/article/details/53413361

标签:python,plsa
0
投稿

猜你喜欢

  • vue动态注册组件实例代码详解

    2023-07-02 17:01:11
  • 快速排序的算法思想及Python版快速排序的实现示例

    2021-10-26 18:04:24
  • “语法错误 (逗号) 在查询表达式id=20, 21”,怎么处理这个逗号?

    2009-09-18 14:52:00
  • 基于mysql replication的问题总结

    2024-01-29 12:50:52
  • Python实现的自定义多线程多进程类示例

    2023-11-16 08:52:15
  • 合并SQL脚本文件的方法分享

    2011-09-30 11:13:03
  • Python 数据结构之队列的实现

    2021-11-28 15:27:26
  • Windows安装Anaconda3的方法及使用过程详解

    2022-03-03 06:20:10
  • MySQL两种表存储结构性能比较测试过程

    2007-12-09 12:45:00
  • mysql unique key在查询中的使用与相关问题

    2024-01-18 20:00:54
  • Pygame游戏开发之太空射击实战子弹与碰撞处理篇

    2022-05-24 03:59:19
  • Python基于文件内容实现查找文件功能

    2022-04-13 11:17:47
  • python爬虫headers设置后无效的解决方法

    2021-09-04 00:55:17
  • Golang使用协程实现批量获取数据

    2024-01-30 05:05:57
  • Django实现图片文字同时提交的方法

    2021-10-19 20:11:28
  • Python中typing模块的具体使用

    2022-03-25 13:02:08
  • php将文件夹打包成zip文件的简单实现方法

    2024-05-11 09:48:14
  • 巧用Dreamweaver MX共享Execl XP文件

    2009-07-14 21:56:00
  • Pytorch实现图像识别之数字识别(附详细注释)

    2022-04-08 08:12:54
  • pyqt 实现在Widgets中显示图片和文字的方法

    2021-12-25 07:28:16
  • asp之家 网络编程 m.aspxhome.com