LDA(Latent Dirichlet Allocation)是一种文档主题生成模型,最近看了点资料,准备使用python实现一下。至于数学模型相关知识,某度一大堆,这里也给出之前参考过的一个挺详细的文档lda算法漫游指南这篇博文只讲算法的sampling方法python实现。完整实现项目开源python-LDA
lda模型变量申请及初始化#
#伪代码#输入:文章集合(分词处理后),K(类的个数)
输出:已经随机分派了一次的lda模型
begin
申请几个统计量:
p 概率向量 维度:K
nw 词在类上的分布 维度:M*K 其中M为文章集合的词的总个数
nwsum 每个类上的词的总数 维度:K
nd 每篇文章中,各个类的词个数分布 维度:V*K 其中V为文章的总个数
ndsum 每篇文章中的词的总个数 维度:V
Z 每个词分派一个类 维度:V*每篇文章词的个数
theta 文章->类的概率分布 维度:V*K
phi 类->词的概率分布 维度:K*M#初始化随机分配类forxin文章数:
统计ndsum[文章id][词的个数]foryin每篇文章的词个数:
给所有词随机分派一个类
词在此类上的分布数目+1此文章中此类的词的个数+1此类的总词数+1end
#
#实现代码片段,更详细看github项目#classLDAModel(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([ [0foryinxrange(dpre.docs[x].length)]forxinxrange(dpre.docs_count)])#M*doc.size(),文档中词的主题分布#随机先分配类型forxinxrange(len(self.Z)):
self.ndsum[x]=self.dpre.docs[x].lengthforyinxrange(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]+= 1self.nd[x][topic]+= 1self.nwsum[topic]+= 1self.theta= np.array([ [0.0foryinxrange(self.K)]forxinxrange(self.dpre.docs_count) ])
self.phi= np.array([ [ 0.0foryinxrange(self.dpre.words_count) ]forxinxrange(self.K)])
sampling抽样过程#
#伪代码#输入:初始化后的lda_model,迭代次数iter_times,超参数α、β,聚类个数K
输出:theta(文章对应类的分布概率),phi(类对应词的分布概率),tassgin(文章中每个词的分派类结果),twords(每个类topN个高频词)
beginforiin迭代次数:formin文章个数:forvin文章中词:
取topic=Z[m][v]
令nw[v][topic]、nwsum[topic]、nd[m][topic]的统计量均-1计算概率p[]#p[]为此词属于每个topic的概率forkin(1,类的个数-1):
p[k]+= p[k-1]
再随机分派一次,记录被分派的新的topic
令nw[v][new_topic]、nwsum[new_topic]、nd[m][new_topic]的统计量均+1#迭代完成后输出模型
end
#代码片段defsampling(self,i,j):
topic=self.Z[i][j]
word=self.dpre.docs[i].words[j]
self.nw[word][topic]-= 1self.nd[i][topic]-= 1self.nwsum[topic]-= 1self.ndsum[i]-= 1Vbeta= 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)forkinxrange(1,self.K):
self.p[k]+= self.p[k-1]
u= random.uniform(0,self.p[self.K-1])fortopicinxrange(self.K):ifself.p[topic]>u:
breakself.nw[word][topic]+=1self.nwsum[topic]+=1self.nd[i][topic]+=1self.ndsum[i]+=1returntopic
此实现为最基础的LDA模型实现,聚类个数K,和超参数的设置要靠人工输入,自动计算的版本会在以后研究。