LDA的Python实现源码
#-*- coding:utf-8 -*-
import logging
import logging.config
import ConfigParser
import numpy as np
import random
import codecs
import os
from collections import OrderedDict
#获取当前路径
path = os.getcwd()
#导入日志配置文件
logging.config.fileConfig("logging.conf")
#创建日志对象
logger = logging.getLogger()
# loggerInfo = logging.getLogger("TimeInfoLogger")
# Consolelogger = logging.getLogger("ConsoleLogger")
#导入配置文件
conf = ConfigParser.ConfigParser()
conf.read("setting.conf")
#文件路径
trainfile = os.path.join(path,os.path.normpath(conf.get("filepath", "trainfile")))
wordidmapfile = os.path.join(path,os.path.normpath(conf.get("filepath","wordidmapfile")))
thetafile = os.path.join(path,os.path.normpath(conf.get("filepath","thetafile")))
phifile = os.path.join(path,os.path.normpath(conf.get("filepath","phifile")))
paramfile = os.path.join(path,os.path.normpath(conf.get("filepath","paramfile")))
topNfile = os.path.join(path,os.path.normpath(conf.get("filepath","topNfile")))
tassginfile = os.path.join(path,os.path.normpath(conf.get("filepath","tassginfile")))
#模型初始参数
K = int(conf.get("model_args","K"))
alpha = float(conf.get("model_args","alpha"))
beta = float(conf.get("model_args","beta"))
iter_times = int(conf.get("model_args","iter_times"))
top_words_num = int(conf.get("model_args","top_words_num"))
class Document(object):
def __init__(self):
self.words = []
self.length = 0
class DataPreProcessing(object):
def __init__(self):
self.docs_count = 0
self.words_count = 0
self.docs = []
self.word2id = OrderedDict()
def cachewordidmap(self):
with codecs.open(wordidmapfile, 'w','utf-8') as f:
for word,id in self.word2id.items():
f.write(word +"\t"+str(id)+"\n")
class LDAModel(object):
def __init__(self,dpre):
self.dpre = dpre #获取预处理参数
#
#模型参数
#聚类个数K,迭代次数iter_times,每个类特征词个数top_words_num,超参数α(alpha) β(beta)
#
self.K = K
self.beta = beta
self.alpha = alpha
self.iter_times = iter_times
self.top_words_num = top_words_num
#
#文件变量
#分好词的文件trainfile
#词对应id文件wordidmapfile
#文章-主题分布文件thetafile
#词-主题分布文件phifile
#每个主题topN词文件topNfile
#最后分派结果文件tassginfile
#模型训练选择的参数文件paramfile
#
self.wordidmapfile = wordidmapfile
self.trainfile = trainfile
self.thetafile = thetafile
self.phifile = phifile
self.topNfile = topNfile
self.tassginfile = tassginfile
self.paramfile = paramfile
# p,概率向量 double类型,存储采样的临时变量
# nw,词word在主题topic上的分布
# nwsum,每各topic的词的总数
# nd,每个doc中各个topic的词的总数
# ndsum,每各doc中词的总数
self.p = np.zeros(self.K)
self.nw = np.zeros((self.dpre.words_count,self.K),dtype="int")
self.nwsum = np.zeros(self.K,dtype="int")
self.nd = np.zeros((self.dpre.docs_count,self.K),dtype="int")
self.ndsum = np.zeros(dpre.docs_count,dtype="int")
self.Z = np.array([ [0 for y in xrange(dpre.docs[x].length)] for x in xrange(dpre.docs_count)]) # M*doc.size(),文档中词的主题分布
#随机先分配类型
for x in xrange(len(self.Z)):
self.ndsum[x] = self.dpre.docs[x].length
for y in xrange(self.dpre.docs[x].length):
topic = random.randint(0,self.K-1)
self.Z[x][y] = topic
self.nw[self.dpre.docs[x].words[y]][topic] += 1
self.nd[x][topic] += 1
self.nwsum[topic] += 1
self.theta = np.array([ [0.0 for y in xrange(self.K)] for x in xrange(self.dpre.docs_count) ])
self.phi = np.array([ [ 0.0 for y in xrange(self.dpre.words_count) ] for x in xrange(self.K)])
def sampling(self,i,j):
topic = self.Z[i][j]
word = self.dpre.docs[i].words[j]
self.nw[word][topic] -= 1
self.nd[i][topic] -= 1
self.nwsum[topic] -= 1
self.ndsum[i] -= 1
Vbeta = self.dpre.words_count * self.beta
Kalpha = self.K * self.alpha
self.p = (self.nw[word] + self.beta)/(self.nwsum + Vbeta) * \
(self.nd[i] + self.alpha) / (self.ndsum[i] + Kalpha)
for k in xrange(1,self.K):
self.p[k] += self.p[k-1]
u = random.uniform(0,self.p[self.K-1])
for topic in xrange(self.K):
if self.p[topic]>u:
break
self.nw[word][topic] +=1
self.nwsum[topic] +=1
self.nd[i][topic] +=1
self.ndsum[i] +=1
return topic
def est(self):
# Consolelogger.info(u"迭代次数为%s 次" % self.iter_times)
for x in xrange(self.iter_times):
for i in xrange(self.dpre.docs_count):
for j in xrange(self.dpre.docs[i].length):
topic = self.sampling(i,j)
self.Z[i][j] = topic
logger.info(u"迭代完成。")
logger.debug(u"计算文章-主题分布")
self._theta()
logger.debug(u"计算词-主题分布")
self._phi()
logger.debug(u"保存模型")
self.save()
def _theta(self):
for i in xrange(self.dpre.docs_count):
self.theta[i] = (self.nd[i]+self.alpha)/(self.ndsum[i]+self.K * self.alpha)
def _phi(self):
for i in xrange(self.K):
self.phi[i] = (self.nw.T[i] + self.beta)/(self.nwsum[i]+self.dpre.words_count * self.beta)
def save(self):
#保存theta文章-主题分布
logger.info(u"文章-主题分布已保存到%s" % self.thetafile)
with codecs.open(self.thetafile,'w') as f:
for x in xrange(self.dpre.docs_count):
for y in xrange(self.K):
f.write(str(self.theta[x][y]) + '\t')
f.write('\n')
#保存phi词-主题分布
logger.info(u"词-主题分布已保存到%s" % self.phifile)
with codecs.open(self.phifile,'w') as f:
for x in xrange(self.K):
for y in xrange(self.dpre.words_count):
f.write(str(self.phi[x][y]) + '\t')
f.write('\n')
#保存参数设置
logger.info(u"参数设置已保存到%s" % self.paramfile)
with codecs.open(self.paramfile,'w','utf-8') as f:
f.write('K=' + str(self.K) + '\n')
f.write('alpha=' + str(self.alpha) + '\n')
f.write('beta=' + str(self.beta) + '\n')
f.write(u'迭代次数 iter_times=' + str(self.iter_times) + '\n')
f.write(u'每个类的高频词显示个数 top_words_num=' + str(self.top_words_num) + '\n')
#保存每个主题topic的词
logger.info(u"主题topN词已保存到%s" % self.topNfile)
with codecs.open(self.topNfile,'w','utf-8') as f:
self.top_words_num = min(self.top_words_num,self.dpre.words_count)
for x in xrange(self.K):
f.write(u'第' + str(x) + u'类:' + '\n')
twords = []
twords = [(n,self.phi[x][n]) for n in xrange(self.dpre.words_count)]
twords.sort(key = lambda i:i[1], reverse= True)
for y in xrange(self.top_words_num):
word = OrderedDict({value:key for key, value in self.dpre.word2id.items()})[twords[y][0]]
f.write('\t'*2+ word +'\t' + str(twords[y][1])+ '\n')
#保存最后退出时,文章的词分派的主题的结果
logger.info(u"文章-词-主题分派结果已保存到%s" % self.tassginfile)
with codecs.open(self.tassginfile,'w') as f:
for x in xrange(self.dpre.docs_count):
for y in xrange(self.dpre.docs[x].length):
f.write(str(self.dpre.docs[x].words[y])+':'+str(self.Z[x][y])+ '\t')
f.write('\n')
logger.info(u"模型训练完成。")
def preprocessing():
logger.info(u'载入数据......')
with codecs.open(trainfile, 'r','utf-8') as f:
docs = f.readlines()
logger.debug(u"载入完成,准备生成字典对象和统计文本数据...")
dpre = DataPreProcessing()
items_idx = 0
for line in docs:
if line != "":
tmp = line.strip().split()
#生成一个文档对象
doc = Document()
for item in tmp:
if dpre.word2id.has_key(item):
doc.words.append(dpre.word2id[item])
else:
dpre.word2id[item] = items_idx
doc.words.append(items_idx)
items_idx += 1
doc.length = len(tmp)
dpre.docs.append(doc)
else:
pass
dpre.docs_count = len(dpre.docs)
dpre.words_count = len(dpre.word2id)
logger.info(u"共有%s个文档" % dpre.docs_count)
dpre.cachewordidmap()
logger.info(u"词与序号对应关系已保存到%s" % wordidmapfile)
return dpre
def run():
dpre = preprocessing()
lda = LDAModel(dpre)
lda.est()
if __name__ == '__main__':
run()
python-LDA
===
### lda模型的python实现,算法采用sampling抽样
---
* 项目基于python2.7.10如果发现计算概率为0,可能是python的兼容性问题,暂时没时间修复(发现python3.0以上版本会出现此问题)
---
### 训练和输出文本格式说明
#### 模型训练文件
`train.dat` 用其他软件or算法分词后,再剔除停用词的最后结果文件,显示格式如下:(一行表示一篇文档)
>1. 康小姐 寮步镇 莞樟路 石井 附近 嘉湖山庄 小区 连续 半夜 停电 已有 居民 咨询 供电公司 小区 电路 正常 咨询 小区 管理处 工作人员 线路 借口 推托<br>
>2. 许小姐 来电反映 寮步镇 莞樟路 汽车东站 附近 嘉湖山庄 小区 最近 一周 都 从 凌晨 3点 早上 8点 停电 昨晚 凌晨 来电 都 没 通电 已有 居民 致电 供电公司 答复 说 该 小区 电路 正常 小区 故意 停电 <br>
>3. 虎门 百佳商场 楼下 乘坐 出租车 虎门 电子城 车牌 粤SLE857 司机 要求 不 打表 需要 20元 要求 打表 司机 拒载<br>
>4. 东城中心 乘坐 粤SM643M 东城 主山高田坊芳桂园 平时 行驶 路线 是 东城 中路 今天 司机 行驶 路线 是 东城大道 东纵大道 温南路 此 车 到了 温南路口车费 是 16元 认为 司机 绕路<br>
#### 模型输出文件
> `model_parameter.dat` 保存模型训练时选择的参数
> `wordidmap.dat` 保存词与id的对应关系,主要用作topN时查询
> `model_twords.dat` 输出每个类高频词topN个
> `model_tassgin.dat` 输出文章中每个词分派的结果,文本格式为词id:类id
> `model_theta.dat` 输出文章与类的分布概率,文本一行表示一篇文章,概率1 概率2 ...表示文章属于类的概率
> `model_phi.dat` 输出词与类的分布概率,是一个K*M的矩阵,其中K为设置分类的个数,M为所有文章的词的总数,
---
### 使用说明
* 用分好词的文本替换掉`data/train.dat`,更详细文档路径查看`setting.conf`
* cd 到lda.py所在目录,执行命令:python lda.py
---
此为lda模型的基础版本,所有参数均由人为设定,更复杂的自动生成算法将在下个版本更新。
LDA的Python实现源码的更多相关文章
- 【转】python:让源码更安全之将py编译成so
python:让源码更安全之将py编译成so 应用场景 Python是一种面向对象的解释型计算机程序设计语言,具有丰富和强大的库,使用其开发产品快速高效. python的解释特性是将py编译为独有的二 ...
- 《python解释器源码剖析》第0章--python的架构与编译python
本系列是以陈儒先生的<python源码剖析>为学习素材,所记录的学习内容.不同的是陈儒先生的<python源码剖析>所剖析的是python2.5,本系列对应的是python3. ...
- python:让源码更安全之将py编译成so
应用场景 Python是一种面向对象的解释型计算机程序设计语言,具有丰富和强大的库,使用其开发产品快速高效. python的解释特性是将py编译为独有的二进制编码pyc文件,然后对pyc中的指令进行解 ...
- 『Python』源码解析_源码文件介绍
本篇代码针对2.X版本,与3.X版本细节不尽相同,由于两者架构差别不大加之本人能力有限,所以就使用2.X体验python的底层原理了. 一.主要文件夹内容 Include :该目录下包含了Python ...
- 『Python』源码解析_从ctype模块理解对象
1.对象的引用计数 从c代码分析可知,python所有对象的内存有着同样的起始结构:引用计数+类型信息,实际上这些信息在python本体重也是可以透过包来一窥一二的, from ctypes impo ...
- 通过阅读python subprocess源码尝试实现非阻塞读取stdout以及非阻塞wait
http://blog.chinaunix.net/uid-23504396-id-4661783.html 执行subprocess的时候,执行不是问题最麻烦的是获取进程执行后的回显来确认是否正确执 ...
- python slots源码分析
上次总结Python3的字典实现后的某一天,突然开窍Python的__slots__的实现应该也是类似,于是翻了翻CPython的源码,果然如此! 关于在自定义类里面添加__slots__的效果,网上 ...
- 神经网络中 BP 算法的原理与 Python 实现源码解析
最近这段时间系统性的学习了 BP 算法后写下了这篇学习笔记,因为能力有限,若有明显错误,还请指正. 什么是梯度下降和链式求导法则 假设我们有一个函数 J(w),如下图所示. 梯度下降示意图 现在,我们 ...
- Linux基础(4)-硬盘分区、格式化及文件系统的管理、软件包的管理、yum管理RPM包和python的源码安装
一: 1) 开启Linux系统前添加一块大小为15G的SCSI硬盘 2) 开启系统,右击桌面,打开终端 3) 为新加的硬盘分区,一个主分区大小为5G,剩余空间给扩展分区,在扩展分区上划分1个逻辑 ...
随机推荐
- HTTP状态码(2xx,3xx,4xx,5xx)
HTTP状态码负责表示客户端请求的返回结果,标记服务器的处理结果. HTTP常用状态码分为5种: 类别 原因短语 1xx Informational(信息状态码) 接受请求正在处理 2xx Suc ...
- i春秋手动病毒查杀
1:查看系统进程程 tasklist命令 2:当任务管理器无法打开的时候可以利用 taskkill /f /im [程序所显示的pid] 两个参数的意思分别是强制和程序在内存中的印象 3:ms ...
- mac tomcat https
一.HTTPS的基本工作原理: HTTPS在传输数据之前需要客户端(浏览器)与服务端(网站)之间进行一次握手,在握手过程中将确立双方加密传输数据的密码信息.TLS/SSL协议不仅仅是一套加密传输的协议 ...
- NET微信公众号开发-5.0微信支付(待测试)
开发前准备. 1.0微信支付官方开发者文档 2.0官方demo下载 我们用c#所以选择.net版本 不过这个官方的demo根本跑步起来 3.0官方demo运行起来解决方案 4.0微信支付官方.net版 ...
- css div上下左右居中
相信大家都会遇到这样的问题,要求一个块上下左右居中,在这里我总结了几个好用的方法 1.已知要居中的块width height 假设 content 要在f里上下左右居中 <div class= ...
- Linux C编程学习之C语言简介---预处理、宏、文件包含……
C的简介 C语言的结构极其紧凑,C语言是一种模块化的编程语言,整个程序可以分割为几个相对独立的功能模块,模块之间的相互调用和数据传递是非常方便的 C语言的表达能力十分强大.C语言兼顾了高级语言和汇编语 ...
- k-means聚类算法python实现
K-means聚类算法 算法优缺点: 优点:容易实现缺点:可能收敛到局部最小值,在大规模数据集上收敛较慢使用数据类型:数值型数据 算法思想 k-means算法实际上就是通过计算不同样本间的距离来判断他 ...
- Deep Learning模型之:CNN卷积神经网络(一)深度解析CNN
http://m.blog.csdn.net/blog/wu010555688/24487301 本文整理了网上几位大牛的博客,详细地讲解了CNN的基础结构与核心思想,欢迎交流. [1]Deep le ...
- 如何查看OpenCv的源代码
需要移植部分opencv的算法,不得不查看opencv的原始代码. 在一般的代码调试中一般只能看到一些opencv的函数声明和定义,看不到内部执行过程,需要利用 CMake导出opencv 源码,生成 ...
- solr连接数据库配置
一般要搜索的信息都是被存储在数据库里面的,但是我们不能直接搜数据库,所以只有借助Solr将要搜索的信息在搜索服务器上进行索引,然后在客户端供客户使用. 一.链接数据库 1. SQL配置 拿SQL Se ...