$ z+ _- s, S3 C; T V; N《美食探索》{美食:0.8,美妆:0.1,其他:0.1} h& J- H d7 O3 x: y
6 L6 r9 r6 m( d
所以想要生成一篇文章,可以先以一定的概率选取上述某个主题,再以一定的概率选取那个主题下的某个单词,不断重复这两步就可以生成最终文章。 6 B7 N$ n4 l j9 |9 \ % |' m1 {6 M+ `. v 在LDA模型中,一篇文档生成的方式如下: - u* y1 v% C. D & K9 P# l- r0 U! q' @8 Z4 V! G6 m, j$ ~5 ]7 P& z
" C2 o2 r: z! ]) T7 ` C9 W2 f
其中,类似Beta分布是二项式分布的共轭先验概率分布,而狄利克雷分布(Dirichlet分布)是多项式分布的共轭先验概率分布。 # b* M) g& N2 j- x% ^& u0 v* K" @: m ' F5 V6 [ P/ G2 ?$ b5 B* }- |6 D2 K* b) ^' N+ |8 \
* \ f. B" W4 \
如果我们要生成一篇文档,它里面的每个词语出现的概率为: : s9 B1 Z! D6 z* a* { 1 o9 f! G0 Y: W8 ?) e9 [9 [2 K. O/ n/ Y
# |: A! {, s0 Q( D! V% ` 更详细的数学推导可以见:通俗理解LDA主题模型_结构之法 算法之道-CSDN博客_lda模型: u R9 [5 b. x2 I" ~
9 C! h: @2 ^, P3 n/ t {
看到文章推断其隐藏的主题分布,就是建模的目的。换言之,人类根据文档生成模型写成了各类文章,然后丢给了计算机,相当于计算机看到的是一篇篇已经写好的文章。现在计算机需要根据一篇篇文章中看到的一系列词归纳出当篇文章的主题,进而得出各个主题各自不同的出现概率:主题分布。0 d5 }2 `, G" L- Y
2 g' q* {4 M; Z8 H
至于LDA主题模型在计算机中具体是怎么实现的,我们也可以不必细究,现在有很多可以直接用来进行LDA主题分析的包,我们直接用就行。(没错,我就是调包侠)1 V0 Y! X3 h+ B( g
. f& n2 f, x# H+ a1 J2 h二、Python实现* L; S5 T! ^5 Z5 v; W+ ~' ` S) [
在用Python进行LDA主题模型分析之前,我先对文档进行了分词和去停用词处理(详情可以看我之前的文章:用python对单一微博文档进行分词——jieba分词(加保留词和停用词)_阿丢是丢心心的博客-CSDN博客_jieba 停用词) : x% y) l7 ?8 s- s& @" y$ B6 r% }+ b j4 Q5 q
我下面的输入文件也是已经分好词的文件 . x4 H7 j. ~# q$ ] 4 F' k% \( ]+ v( n1.导入算法包 $ I2 a: [; M5 c, Timport gensim3 a6 H b$ [; `; J& s- v
from gensim import corpora0 W7 h% v4 x) W t' U
import matplotlib.pyplot as plt - t' ?6 x) p1 bimport matplotlib4 |$ w2 w8 \7 ^( I6 F2 r2 i" k( S
import numpy as np: [. r9 s: n- A% @; U
import warnings 5 h8 s* i0 }! U/ Y* f! Zwarnings.filterwarnings('ignore') # To ignore all warnings that arise here to enhance clarity 3 s+ H$ ^0 L6 d0 y % v$ I7 I6 T; {% }- Cfrom gensim.models.coherencemodel import CoherenceModel, O; O, T" [0 N* h
from gensim.models.ldamodel import LdaModel & G8 ?6 } o; s: M, i; o2.加载数据7 n+ C6 C. w2 R8 q
先将文档转化为一个二元列表,其中每个子列表代表一条微博: 8 o2 _0 m/ [$ r& Z: l* |. \- `1 n6 {+ v
PATH = "E:/data/output.csv"& }4 m7 w' i& J5 \
# j" z- ~6 y4 ~7 Z' G2 m: k8 yfile_object2=open(PATH,encoding = 'utf-8',errors = 'ignore').read().split('\n') #一行行的读取内容7 w3 v5 u) z; Q0 e
data_set=[] #建立存储分词的列表) b9 r) C, j% G9 e8 c
for i in range(len(file_object2)): 3 {6 z/ Q7 o/ r# O1 Y! ~* g, C result=[]5 g% z I( H- a' E" \3 J$ G% P
seg_list = file_object2.split() $ u6 s/ x* K8 B$ \1 D( Y for w in seg_list : #读取每一行分词 3 E" J6 A H0 t/ ^2 x result.append(w): I' I5 J7 Z) }
data_set.append(result)6 C, {/ P+ M+ \ U
print(data_set)3 p$ R3 N: h; e- l* U
构建词典,语料向量化表示: % Q$ Y- }1 f8 F* i f# [6 [5 W, t/ f" f% Z% q @/ @$ Z: b; ~
dictionary = corpora.Dictionary(data_set) # 构建词典 1 _ t$ W8 l9 I2 x2 B6 s% U: wcorpus = [dictionary.doc2bow(text) for text in data_set] #表示为第几个单词出现了几次 8 s( P A3 t$ _ V3.构建LDA模型3 E$ J: O$ G. E2 J" j% `3 M
ldamodel = LdaModel(corpus, num_topics=10, id2word = dictionary, passes=30,random_state = 1) #分为10个主题 " z$ ~1 D$ M' H& g+ jprint(ldamodel.print_topics(num_topics=num_topics, num_words=15)) #每个主题输出15个单词 : A1 y) f, s L2 v$ W 这是确定主题数时LDA模型的构建方法,一般我们可以用指标来评估模型好坏,也可以用这些指标来确定最优主题数。一般用来评价LDA主题模型的指标有困惑度(perplexity)和主题一致性(coherence),困惑度越低或者一致性越高说明模型越好。一些研究表明perplexity并不是一个好的指标,所以一般我用coherence来评价模型并选择最优主题,但下面代码两种方法我都用了。 6 ^" \' z) b4 Q5 [* ` ) K0 `2 f' A8 A9 |#计算困惑度8 w. u X0 Y9 F0 d7 N1 d' _: Z$ M
def perplexity(num_topics): 6 J/ n' r! E3 a3 W% i9 F/ t# s ldamodel = LdaModel(corpus, num_topics=num_topics, id2word = dictionary, passes=30) - S7 g' A; ~/ r! \ print(ldamodel.print_topics(num_topics=num_topics, num_words=15)) 8 a" o% k# s( M7 w) [ print(ldamodel.log_perplexity(corpus)); m6 z* ~# x! j# n
return ldamodel.log_perplexity(corpus) 0 e& D' |" y0 f3 f#计算coherence7 { y6 X+ {0 o) j( K& K+ p
def coherence(num_topics):- h; d9 z- h2 w
ldamodel = LdaModel(corpus, num_topics=num_topics, id2word = dictionary, passes=30,random_state = 1)2 D( s4 m9 t1 D Y
print(ldamodel.print_topics(num_topics=num_topics, num_words=10))$ U* P4 Q0 {4 }: y; |
ldacm = CoherenceModel(model=ldamodel, texts=data_set, dictionary=dictionary, coherence='c_v') ' A8 T0 l- M. L9 _! B print(ldacm.get_coherence())4 v A( v8 K8 |, B5 n9 p
return ldacm.get_coherence()- S! X3 Q& v( S$ e2 i6 z+ b2 U: R
4.绘制主题-coherence曲线,选择最佳主题数 . q* l. J$ Y. I" Z5 s/ `x = range(1,15)# w9 P) x! f# A& q
# z = [perplexity(i) for i in x] #如果想用困惑度就选这个 2 m5 u. {9 [& Q1 _/ C, I ~y = [coherence(i) for i in x]) @ F% t# f, w7 J5 {. d
plt.plot(x, y) $ T1 A+ N5 @8 Gplt.xlabel('主题数目')8 L B8 l# Y$ q3 r$ w
plt.ylabel('coherence大小')) R$ \& G3 y" Y3 C, z
plt.rcParams['font.sans-serif']=['SimHei']0 Q/ Z0 {* o' ~7 ~
matplotlib.rcParams['axes.unicode_minus']=False + q X2 U' A" q3 L0 }) r Q6 jplt.title('主题-coherence变化情况') * K+ @4 m! F6 Iplt.show()1 d$ Z0 L& x8 n
最终能得到各主题的词语分布和这样的图形: - @- j4 [4 _! z7 O! q1 A * k) E1 B, |/ R" m* e/ S& T" [+ h7 b) G* v5 ~; R% n/ d
, P7 U' I7 T2 b8 J+ Y3 Y/ O% A 5.结果输出与可视化' p& M; }% ?5 F9 v% {8 O. e
通过上述主题评估,我们发现可以选择5作为主题个数,接下来我们可以再跑一次模型,设定主题数为5,并输出每个文档最有可能对应的主题" `3 {5 A3 r1 }& V
: Q6 ]& u# P Y3 w8 cfrom gensim.models import LdaModel$ e% ^- J+ z" }) v! \. U) h
import pandas as pd ' @/ f v! ]! Z, m) g0 f, ~from gensim.corpora import Dictionary $ n7 ^2 u9 }% m) F& Tfrom gensim import corpora, models , G# ]6 d/ L9 s& r- e/ rimport csv# q Y5 R/ P/ S7 q+ Y
/ y" m5 |( ~$ s* u
# 准备数据 # S' j5 Y# H1 m2 [2 M# z/ w8 bPATH = "E:/data/output1.csv"9 V, \+ M8 k* W6 b
" U: V; U9 _- c1 {1 m: ~" O, b, Ofile_object2=open(PATH,encoding = 'utf-8',errors = 'ignore').read().split('\n') #一行行的读取内容 ~$ D. Q# p4 W0 fdata_set=[] #建立存储分词的列表 A8 Y! R7 A0 h* O' D0 T
for i in range(len(file_object2)):6 f% X4 x3 R) M) G
result=[] " i j: h3 k0 ~' y7 i5 _; W seg_list = file_object2.split()' U# Z' v2 J4 o7 _( w% X! u" @
for w in seg_list :#读取每一行分词+ A0 u7 Z* i# ]/ j6 [8 w8 I
result.append(w) 1 ~3 d- ~, u6 ~( F" _# ~5 O5 P, G data_set.append(result)! u( D- W4 \) _ Q
5 f2 e9 O b% X5 z/ Fdictionary = corpora.Dictionary(data_set) # 构建词典3 n; N; N; E& u1 o( p, l7 w( S
corpus = [dictionary.doc2bow(text) for text in data_set]! L; l8 H( ^. O/ l
5 F6 p6 w0 |. d3 I5 E% r' ]) Plda = LdaModel(corpus=corpus, id2word=dictionary, num_topics=5, passes = 30,random_state=1)2 f! U2 _5 B, [% z: U2 ?: D+ X
topic_list=lda.print_topics() & W& ]% o1 G6 F+ p8 dprint(topic_list) 4 H7 \( ?0 C' s4 r) m ) z7 r2 y# {7 Y7 @ ` L6 o# jfor i in lda.get_document_topics(corpus)[:]: : r) P* T' K- y F! [ listj=[] ) [6 f9 N3 G5 Z. S ~ for j in i: % q. A' w0 u) P1 g) k7 T+ a listj.append(j[1]) . a4 w! ?' C2 w; m5 G1 V5 Z0 ~ bz=listj.index(max(listj)) 0 w9 {! R& z2 S* f% E print(i[bz][0])3 S: F9 f% ?- \ ]8 S4 c+ N, m
- v Y, s' F* F, S% H D9 U6 W- M1 Q 同时我们可以用pyLDAvis对LDA模型结果进行可视化: ; o; u5 N+ y: [2 w' Y( K- j4 X- s7 O9 T0 G2 W9 l+ t& |; ?
import pyLDAvis.gensim% C( x# i/ [5 s* J$ b* I
pyLDAvis.enable_notebook()2 u$ X4 r, I% F$ z9 F$ Q4 _
data = pyLDAvis.gensim.prepare(lda, corpus, dictionary)2 B+ I( _4 i) G+ N" M/ z
pyLDAvis.save_html(data, 'E:/data/3topic.html')" n) M& d$ z. k2 C" K+ F
大概能得到这样的结果:# y/ K3 t$ j& e8 ^, t% L
, w( E( D$ @ T " t; u/ R0 K6 @0 t: L( X2 X; h3 [. T5 {3 D2 s: ` g) }2 ~/ O% x
左侧圆圈表示主题,右侧表示各个词语对主题的贡献度。5 r2 x) w% ?% k2 @0 [" e
6 M0 F$ v$ H5 y+ b
所有代码如下: 4 C6 Z& ^1 Y3 l. Gimport gensim0 {' x3 Y: x6 {9 |' f
from gensim import corpora: v8 s& S. \7 I
import matplotlib.pyplot as plt0 {* t$ @0 V/ n+ e
import matplotlib6 R: P4 G4 J1 C3 i2 [. H
import numpy as np ' J( d, E1 K4 i) ^/ timport warnings - K. R1 W z5 L1 \- _warnings.filterwarnings('ignore') # To ignore all warnings that arise here to enhance clarity% ^1 l0 x& D7 Y* I- _ S9 G
+ d& `7 Q' N2 Y" Z5 W9 V3 \* E
from gensim.models.coherencemodel import CoherenceModel & g0 d, h! f1 e% j. v& Kfrom gensim.models.ldamodel import LdaModel ) j" n& W! F# n, w1 v2 i# U) g/ q1 j! @, a; {
3 r% W$ j/ Q+ ^4 Q" s* v
5 k0 {$ N; I& r
# 准备数据" P: w- j8 Q) t
PATH = "E:/data/output.csv"- k- V; c! n( f4 R5 s: j8 N
0 V- I i' e* t4 efile_object2=open(PATH,encoding = 'utf-8',errors = 'ignore').read().split('\n') #一行行的读取内容 + _+ V! v' ^/ n7 e: l. qdata_set=[] #建立存储分词的列表1 Z0 r& L6 o9 {; Q! N1 x
for i in range(len(file_object2)): ; [. R8 E+ {/ c( S. h result=[] 4 o1 C2 \8 j6 c/ a2 H seg_list = file_object2.split() . [) H z0 d$ M/ P3 U7 r for w in seg_list :#读取每一行分词 4 c4 Y9 Y' N# c0 R+ b& d result.append(w)( H E4 n6 [! \" a- {
data_set.append(result)/ F# O5 e4 J3 ^+ F- F- D
print(data_set) ; `7 V$ E$ q7 C8 D1 A8 ~( G% `7 a+ _3 j5 C1 X
1 k& |3 [8 R3 G7 m( O
dictionary = corpora.Dictionary(data_set) # 构建 document-term matrix* c( u8 O& S1 [6 @+ {( X
corpus = [dictionary.doc2bow(text) for text in data_set] . C! S6 v) P7 E* `5 Q2 u#Lda = gensim.models.ldamodel.LdaModel # 创建LDA对象 ' o; }/ Z8 D0 G! L. y. W+ E0 }( O5 P6 H M* q2 N/ b# K+ s
#计算困惑度 # W9 f3 I+ }5 Odef perplexity(num_topics):: T& K+ Y, F! a& y. } P8 E
ldamodel = LdaModel(corpus, num_topics=num_topics, id2word = dictionary, passes=30); ` I5 `1 o6 n J) N' ]- P
print(ldamodel.print_topics(num_topics=num_topics, num_words=15)) H/ M. A. S/ b9 N
print(ldamodel.log_perplexity(corpus))7 H0 j. z2 g# l- \$ l
return ldamodel.log_perplexity(corpus)( ?, I W; p6 H: k5 m
# i5 l! u% \/ @/ M+ t% H
#计算coherence / ]) C! l8 e& i( l4 _def coherence(num_topics): 0 E3 o5 P: U& l8 M3 p ldamodel = LdaModel(corpus, num_topics=num_topics, id2word = dictionary, passes=30,random_state = 1) 3 e9 T0 c( Z* m5 F" G( h; ? print(ldamodel.print_topics(num_topics=num_topics, num_words=10)) ( Q- l& ~ K, m% q ldacm = CoherenceModel(model=ldamodel, texts=data_set, dictionary=dictionary, coherence='c_v') ' T9 M& s% m2 a5 r+ d! ]' }' ^8 G print(ldacm.get_coherence())5 v* Q+ V5 j" x* o( D) N' s
return ldacm.get_coherence()8 K r9 Q E- y% @
! l& A: d6 w, l1 I7 [
# 绘制困惑度折线图( K* b$ \1 T" Y0 B! x
x = range(1,15) ( ^! i; {# d! C" A5 D% j, n2 Y3 f# z = [perplexity(i) for i in x] h( u1 A. }0 n/ s5 n; Py = [coherence(i) for i in x] ; [- q( x% S' B9 E9 J' Eplt.plot(x, y) H5 y" \9 N. W; p" r: N% f% K& C/ ~/ `
plt.xlabel('主题数目')5 m2 ]4 k: t: ]( Q- l
plt.ylabel('coherence大小') . \. n; Y Z- v0 j& ^plt.rcParams['font.sans-serif']=['SimHei'] - w7 v8 a5 f! [" Umatplotlib.rcParams['axes.unicode_minus']=False " e$ H9 G7 A0 d( iplt.title('主题-coherence变化情况') 2 J: ?7 I$ U! [plt.show()9 O3 h0 J% O+ c) M# J5 V1 d
5 i3 v7 V/ y; t; L- i. u* u; {from gensim.models import LdaModel ' o1 F4 R2 K1 M/ P5 cimport pandas as pd ' i. [7 F/ s, ?: u1 bfrom gensim.corpora import Dictionary . C2 u8 a* n G0 ]. l6 E% yfrom gensim import corpora, models- ]5 z2 a3 W- r: _7 D
import csv $ T. s' b) Y1 Y$ ?: Q' M/ d+ S- [% p8 m9 j" |
# 准备数据# P0 W J, ^+ Q1 B4 w; M6 T
PATH = "E:/data/output1.csv" 5 Q2 p. v5 e, O# r( v$ c' L | 7 S7 [7 A5 l/ u# Qfile_object2=open(PATH,encoding = 'utf-8',errors = 'ignore').read().split('\n') #一行行的读取内容 & q7 @; d# k8 X$ x- Qdata_set=[] #建立存储分词的列表 * P' X j" B; A" ~* h' Ifor i in range(len(file_object2)): 8 B7 P' J a6 c8 x9 ~+ L result=[]9 t! H8 `0 Q. B7 J3 ^; N
seg_list = file_object2.split()# J7 `- J t/ }* w! v
for w in seg_list :#读取每一行分词 + m4 o& V& g6 N% ? result.append(w) 1 y9 ^: D. b7 T, ? data_set.append(result)) N: c/ |# x9 k
t( n8 u+ A4 L2 p5 y. |: @$ F& Pdictionary = corpora.Dictionary(data_set) # 构建 document-term matrix* P' O5 Y, j. a$ q
corpus = [dictionary.doc2bow(text) for text in data_set] e$ e' T9 N' m5 w$ {! N ; F S3 P8 D' l: mlda = LdaModel(corpus=corpus, id2word=dictionary, num_topics=5, passes = 30,random_state=1) ) w; p1 g3 m+ b5 U$ c& c% I" M, {% Jtopic_list=lda.print_topics()- L4 m! w/ t, G
print(topic_list)6 @* u V' r) t8 S2 o
5 x4 F5 J" X! c$ r [# g! l* N5 A# Rresult_list =[], d3 n- P4 d% K
for i in lda.get_document_topics(corpus)[:]: 3 @. Z+ ^) _& m8 F e listj=[]5 ]# |' k) F& Z) ?8 \
for j in i: 1 m, j# o$ v& n- ? listj.append(j[1]) 5 c) L' ?5 v6 `/ n$ S1 S/ S bz=listj.index(max(listj)) : i1 x: [5 Q) Z8 t) S; P1 V3 i result_list.append(i[bz][0])3 T6 M: S b1 U( u6 v8 \9 p7 O. O
print(result_list) ) I5 D4 Y( c. Y+ p4 _8 A1 Q: o) q( x: Y
import pyLDAvis.gensim5 m4 K/ {6 ?/ X
pyLDAvis.enable_notebook() 5 c4 L2 f/ C( k6 v. w: mdata = pyLDAvis.gensim.prepare(lda, corpus, dictionary) ( I/ h$ U( [1 h a3 \1 [7 [) ypyLDAvis.save_html(data, 'E:/data/topic.html') 7 l8 U- K+ O1 C/ B有需要自取~+ t4 Y; F: _7 U* Q6 V$ P: N
————————————————% L) l9 @9 o! k- w' W3 c
版权声明:本文为CSDN博主「阿丢是丢心心」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。/ G) O6 M9 T. \4 }% B6 a$ m
原文链接:https://blog.csdn.net/weixin_41168304/article/details/122389948 / D; ~2 _) K6 F! E, C / H; H: O( W4 i) r7 y2 s1 y' e( z 2 M. P) f: Y! D* z2 [" _# O' o