定义
输入:
单词集合
W
=
{
ω
1
,
⋯
,
ω
v
,
⋯
,
ω
V
}
,
其中
ω
v
是第
v
个单词
,
v
=
1
,
2
,
⋯
,
V
,
V
是单词第个数。
单词集合W = \{ \omega_1,\cdots,\omega_v,\cdots,\omega_V \},其中\omega_v是第v个单词,v = 1,2,\cdots,V,V是单词第个数。
单词集合W={ω1,⋯,ωv,⋯,ωV},其中ωv是第v个单词,v=1,2,⋯,V,V是单词第个数。
文本集合
D
=
{
w
1
,
⋯
,
w
m
,
⋯
,
w
M
}
,
其中
w
m
是第
m
个文本
,
m
=
1
,
2
,
⋯
,
M
,
M
是文本的个数。
文本集合D = \{ w_1,\cdots,w_m,\cdots,w_M\},其中w_m是第m个文本,m=1,2,\cdots,M,M是文本的个数。
文本集合D={w1,⋯,wm,⋯,wM},其中wm是第m个文本,m=1,2,⋯,M,M是文本的个数。
,
文本
w
m
是一个单词序列
w
m
=
(
ω
m
1
,
⋯
,
ω
m
n
,
⋯
,
ω
m
N
n
)
,
w
m
n
是文本
w
m
的第
n
个单词
文本w_m是一个单词序列w_m = (\omega_{m1},\cdots,\omega_{mn},\cdots,\omega_mN_n),w_{mn}是文本w_m的第n个单词
文本wm是一个单词序列wm=(ωm1,⋯,ωmn,⋯,ωmNn),wmn是文本wm的第n个单词
,
n
=
1
,
2
,
⋯
,
N
m
,
N
m
是文本
w
m
中单词第个数。
,n=1,2,\cdots,N_m,N_m是文本w_m中单词第个数。
,n=1,2,⋯,Nm,Nm是文本wm中单词第个数。
话题集合
Z
=
{
z
1
,
⋯
,
z
k
,
⋯
,
z
K
}
,
其中
z
k
是第
k
个话题
,
k
=
1
,
2
,
⋯
,
K
,
K
是话题的个数
话题集合Z = \{ z_1,\cdots,z_k,\cdots,z_K \},其中z_k是第k个话题,k=1,2,\cdots,K,K是话题的个数
话题集合Z={z1,⋯,zk,⋯,zK},其中zk是第k个话题,k=1,2,⋯,K,K是话题的个数。
狄利克雷分布的超参数
α
,
其中
α
为
K
维向量
,
α
=
(
α
1
,
α
2
,
⋯
,
α
K
)
\alpha,其中\alpha为K维向量,\alpha = (\alpha_1,\alpha_2,\cdots,\alpha_K)
α,其中α为K维向量,α=(α1,α2,⋯,αK)
狄利克雷分布的超参数
β
,
其中
β
为
V
维向量
,
β
=
(
β
1
,
β
2
,
⋯
,
β
V
)
\beta,其中\beta为V维向量,\beta = (\beta_1,\beta_2,\cdots,\beta_V)
β,其中β为V维向量,β=(β1,β2,⋯,βV)
输出:
θ
:
θ
=
{
θ
m
}
m
=
1
M
,
每一个文本
w
m
由一个话题的条件概率分布
p
(
z
∣
w
m
)
决定
,
z
∈
Z
。分布
p
(
z
∣
w
m
)
服从多项分布
(
严格意义上类别分布
)
\theta:\theta = \{ \theta_m \}_{m=1}^M,每一个文本w_m由一个话题的条件概率分布p(z|w_m)决定,z \in Z。分布p(z|w_m)服从多项分布(严格意义上类别分布)
θ:θ={θm}m=1M,每一个文本wm由一个话题的条件概率分布p(z∣wm)决定,z∈Z。分布p(z∣wm)服从多项分布(严格意义上类别分布)
,
其参数为
θ
m
,
参数
θ
m
服从超参数为
α
的狄利克雷分布
(
先验分布
)
其参数为\theta_m,参数\theta_m服从超参数为\alpha的狄利克雷分布(先验分布)
其参数为θm,参数θm服从超参数为α的狄利克雷分布(先验分布)
φ
:
φ
=
{
φ
m
}
m
=
1
M
,
每一个话题
z
k
由一个单词的条件概率分布
p
(
ω
∣
z
k
)
决定
,
ω
∈
W
。分布
p
(
ω
∣
z
k
)
服从多项分布
(
严格意义上类别分布
)
\varphi:\varphi = \{ \varphi_m \}_{m=1}^M,每一个话题z_k由一个单词的条件概率分布p(\omega|z_k)决定,\omega \in W。分布p(\omega|z_k)服从多项分布(严格意义上类别分布)
φ:φ={φm}m=1M,每一个话题zk由一个单词的条件概率分布p(ω∣zk)决定,ω∈W。分布p(ω∣zk)服从多项分布(严格意义上类别分布)
,
其参数为
φ
k
,
参数
φ
k
服从超参数为
β
的狄利克雷分布
(
先验分布
)
其参数为\varphi_k,参数\varphi_k服从超参数为\beta的狄利克雷分布(先验分布)
其参数为φk,参数φk服从超参数为β的狄利克雷分布(先验分布)
(1)生成话题的单词分布
随机生成K个话题的单词分布。按照狄利克雷分布
D
i
r
(
β
)
随机生成一个参数向量
φ
k
,
φ
k
∼
D
i
r
(
β
)
,
作为话题
z
k
的单词分布
p
(
ω
∣
z
k
)
,
ω
∈
W
,
k
=
1
,
2
,
⋯
,
K
。
Dir(\beta)随机生成一个参数向量\varphi_k,\varphi_k \sim Dir(\beta),作为话题z_k的单词分布p(\omega|z_k),\omega \in W,k=1,2,\cdots,K。
Dir(β)随机生成一个参数向量φk,φk∼Dir(β),作为话题zk的单词分布p(ω∣zk),ω∈W,k=1,2,⋯,K。
(2)生成文本的话题分布
随机生成M个文本的话题分布。按照狄利克雷分布
D
i
r
(
α
)
随机生成一个参数向量
θ
m
,
θ
m
∼
D
i
r
(
α
)
,
作为文本
w
m
的话题分布
p
(
z
∣
w
m
)
,
m
=
1
,
2
,
⋯
,
M
。
Dir(\alpha)随机生成一个参数向量\theta_m,\theta_m \sim Dir(\alpha),作为文本w_m的话题分布p(z|w_m),m=1,2,\cdots,M。
Dir(α)随机生成一个参数向量θm,θm∼Dir(α),作为文本wm的话题分布p(z∣wm),m=1,2,⋯,M。
(3)生成文本的单词序列
随机生成
M
个文本的
N
m
个单词。文本
w
m
(
m
=
1
,
2
,
⋯
,
M
)
的单词
w
m
n
(
n
−
1
,
2
,
⋯
,
N
m
)
的生成过程如下
:
随机生成M个文本的N_m个单词。文本w_m(m=1,2,\cdots,M)的单词w_{mn}(n-1,2,\cdots,N_m)的生成过程如下:
随机生成M个文本的Nm个单词。文本wm(m=1,2,⋯,M)的单词wmn(n−1,2,⋯,Nm)的生成过程如下:
(3-1)
首先按照多项分布
M
u
l
t
(
θ
m
)
随机生成一个话题
z
m
n
,
z
m
n
∼
M
u
l
t
(
θ
m
)
首先按照多项分布Mult(\theta_m)随机生成一个话题z_{mn},z_{mn} \sim Mult(\theta_m)
首先按照多项分布Mult(θm)随机生成一个话题zmn,zmn∼Mult(θm)。
(3-2)
然后按照多项分布
M
u
l
t
(
φ
Z
m
n
)
随机生成一个单词
ω
m
n
,
ω
m
n
∼
M
u
l
t
(
φ
Z
m
n
)
。
然后按照多项分布Mult(\varphi_{Zmn})随机生成一个单词\omega_{mn},\omega_{mn} \sim Mult(\varphi_{Zmn})。
然后按照多项分布Mult(φZmn)随机生成一个单词ωmn,ωmn∼Mult(φZmn)。
文本
w
m
本身是单词序列
w
m
=
(
ω
m
1
,
ω
m
2
,
⋯
,
ω
m
N
m
)
,
对应着隐式的话题序列
z
m
=
(
z
m
1
,
z
m
2
,
⋯
,
z
m
N
m
)
文本w_m本身是单词序列w_m = ( \omega_{m1},\omega_{m2},\cdots,\omega_{mNm} ),对应着隐式的话题序列z_m = ( z_{m1},z_{m2},\cdots,z_{mNm} )
文本wm本身是单词序列wm=(ωm1,ωm2,⋯,ωmNm),对应着隐式的话题序列zm=(zm1,zm2,⋯,zmNm)。
输入空间
W
=
{
ω
1
,
⋯
,
ω
v
,
⋯
,
ω
V
}
W = \{ \omega_1,\cdots,\omega_v,\cdots,\omega_V \}
W={ω1,⋯,ωv,⋯,ωV}
D
=
{
w
1
,
⋯
,
w
m
,
⋯
,
w
M
}
D = \{ w_1,\cdots,w_m,\cdots,w_M \}
D={w1,⋯,wm,⋯,wM}
α
=
(
α
1
,
α
2
,
⋯
,
α
K
)
\alpha = (\alpha_1,\alpha_2,\cdots,\alpha_K)
α=(α1,α2,⋯,αK)
β
=
(
β
1
,
β
2
,
⋯
,
β
V
)
\beta = (\beta_1,\beta_2,\cdots,\beta_V)
β=(β1,β2,⋯,βV)
狄利克雷分布,
θ
∼
D
i
r
(
α
)
\theta \sim Dir(\alpha)
θ∼Dir(α)
若多远连续随机变量
θ
=
(
θ
1
,
θ
2
,
⋯
,
θ
k
)
的概率密度函数为
若多远连续随机变量\theta = (\theta_1,\theta_2,\cdots,\theta_k)的概率密度函数为
若多远连续随机变量θ=(θ1,θ2,⋯,θk)的概率密度函数为
p
(
θ
∣
α
)
=
Γ
(
∑
i
=
1
k
α
i
)
∏
i
=
1
k
Γ
(
α
i
)
∏
i
=
1
k
θ
i
α
i
−
1
,
∑
i
=
1
k
α
i
=
1
,
θ
i
≥
0
,
i
=
1
,
2
,
⋯
,
k
,
Γ
(
s
)
=
∫
0
∞
x
s
−
1
e
−
x
d
x
,
s
>
0
,
Γ
(
s
+
1
)
=
s
Γ
(
s
)
p(\theta|\alpha) = \dfrac{\Gamma(\sum_{i=1}^k \alpha_i)}{\prod_{i=1}^k \Gamma(\alpha_i)} \prod_{i=1}^k \theta_i^{\alpha_i-1},\sum_{i=1}^k \alpha_i = 1,\theta_i \geq 0,i=1,2,\cdots,k,\Gamma(s) = \int_0^{\infty}x^{s-1}e^{-x}d_x,s>0,\Gamma(s+1)=s\Gamma(s)
p(θ∣α)=∏i=1kΓ(αi)Γ(∑i=1kαi)i=1∏kθiαi−1,i=1∑kαi=1,θi≥0,i=1,2,⋯,k,Γ(s)=∫0∞xs−1e−xdx,s>0,Γ(s+1)=sΓ(s)
Γ
(
s
+
1
)
=
s
!
\Gamma(s+1)=s!
Γ(s+1)=s!
import numpy as np
import pandas as pd
import string
# import nltk
# nltk.download('stopwords') #离线下载地址:https://download.csdn.net/download/nanxiaotao/89743735,注需放置对应ENV的/nltk_data/corpora/stopwords目录下
from nltk.corpus import stopwords
import time
#定义加载数据的函数
def load_data(file, K):
'''
数据集 下载地址:https://download.csdn.net/download/nanxiaotao/89743739
INPUT:
file - (str) 数据文件的路径
K - (int) 设定的话题数
OUTPUT:
org_topics - (list) 原始话题标签列表
text - (list) 文本列表
words - (list) 单词列表
alpha - (list) 话题概率分布,模型超参数
beta - (list) 单词概率分布,模型超参数
'''
df = pd.read_csv(file) #读取文件
org_topics = df['category'].unique().tolist()
M = df.shape[0] #文本数
alpha = np.zeros(K)
beta = np.zeros(1000)
for k, topic in enumerate(org_topics):
alpha[k] = df[df['category'] == topic].shape[0] / M
df.drop('category', axis=1, inplace=True)
n = df.shape[0]
text = []
words = []
for i in df['text'].values:
t = i.translate(str.maketrans('', '', string.punctuation))
t = [j for j in t.split() if j not in stopwords.words('english')]
t = [j for j in t if len(j) > 3]
text.append(t)
words.extend(set(t))
words = list(set(words))
words_cnt = np.zeros(len(words))
for i in range(len(text)):
t = text[i]
for w in t:
ind = words.index(w)
words_cnt[ind] += 1
sort_inds = np.argsort(words_cnt)[::-1]
words = [words[ind] for ind in sort_inds[:1000]]
for i in range(len(text)):
t = []
for w in text[i]:
if w in words:
ind = words.index(w)
t.append(w)
beta[ind] += 1
text[i] = t
beta /= np.sum(beta)
return org_topics, text, words, alpha, beta
K = 5 #设定话题数为5
org_topics, text, words, alpha, beta = load_data('bbc_text.csv', K) #加载数据
print('Original Topics:')
print(org_topics) #打印原始的话题标签列表
np.shape(text)
np.shape(words)
np.shape(alpha)
np.shape(beta)
算法
对所有文本
w
m
,
m
=
1
,
2
,
⋯
,
M
,
对第
m
个文本中的所有单词
ω
m
n
,
n
=
1
,
2
,
⋯
,
N
m
对所有文本w_m,m=1,2,\cdots,M,对第m个文本中的所有单词\omega_{mn},n=1,2,\cdots,N_m
对所有文本wm,m=1,2,⋯,M,对第m个文本中的所有单词ωmn,n=1,2,⋯,Nm
抽样话题
z
m
n
=
z
k
∼
M
u
l
t
(
1
K
)
:
抽样话题z_{mn} = z_k \sim Mult(\frac{1}{K}):
抽样话题zmn=zk∼Mult(K1):
增加文本
−
话题计数
n
m
k
=
n
m
k
+
1
增加文本-话题计数n_{mk} = n_{mk}+1
增加文本−话题计数nmk=nmk+1
增加文本
−
话题计数
n
m
=
n
m
+
1
增加文本-话题计数n_m = n_m + 1
增加文本−话题计数nm=nm+1
增加话题
−
单词计数
n
k
v
=
n
k
v
+
1
增加话题-单词计数n_{kv} = n_{kv} + 1
增加话题−单词计数nkv=nkv+1
增加话题
−
单词计数
n
k
=
n
k
+
1
增加话题-单词计数n_k= n_k + 1
增加话题−单词计数nk=nk+1
对所有文本
w
m
,
m
=
1
,
2
,
⋯
,
M
,
对第
m
个文本中的所有单词
ω
m
n
,
n
=
1
,
2
,
⋯
,
N
m
对所有文本w_m,m=1,2,\cdots,M,对第m个文本中的所有单词\omega_{mn},n=1,2,\cdots,N_m
对所有文本wm,m=1,2,⋯,M,对第m个文本中的所有单词ωmn,n=1,2,⋯,Nm
(
a
)
当前的单词
ω
m
n
是第
v
个单词
,
话题指派
z
m
n
是第
k
个话题
;
(a)当前的单词\omega_{mn}是第v个单词,话题指派z_{mn}是第k个话题;
(a)当前的单词ωmn是第v个单词,话题指派zmn是第k个话题;
减少计数
n
m
k
=
n
m
k
−
1
,
n
m
=
n
m
−
1
,
n
k
v
=
n
k
v
−
1
,
n
k
=
n
k
−
1
;
减少计数n_{mk}=n_{mk}-1,n_m=n_m-1,n_{kv}=n_{kv}-1,n_k=n_k-1;
减少计数nmk=nmk−1,nm=nm−1,nkv=nkv−1,nk=nk−1;
(
b
)
按照满条件分布进行抽样
(b)按照满条件分布进行抽样
(b)按照满条件分布进行抽样
p
(
z
i
∣
z
−
i
,
w
,
α
,
β
)
∝
n
k
v
+
β
v
∑
v
=
1
V
(
n
k
v
+
β
v
)
⋅
n
m
k
+
α
k
∑
k
=
1
K
(
n
m
k
+
α
k
)
p(z_i|z_{-i},w,\alpha,\beta) \propto \dfrac{n_{kv} + \beta_v}{\sum_{v=1}^V(n_{kv} + \beta_v)} \cdot \dfrac{n_{mk} + \alpha_k}{\sum_{k=1}^K(n_{mk}+\alpha_k)}
p(zi∣z−i,w,α,β)∝∑v=1V(nkv+βv)nkv+βv⋅∑k=1K(nmk+αk)nmk+αk
得到新的第
k
′
个话题
,
分配给
z
m
n
k^{'}个话题,分配给z_{mn}
k′个话题,分配给zmn;
(
c
)
增加计数
n
m
k
′
=
n
m
k
′
+
1
,
n
m
=
n
m
+
1
,
n
k
′
v
=
n
k
′
v
+
1
,
n
k
′
=
n
k
′
+
1
(c)增加计数n_{mk^{'}} = n_{mk^{'}} + 1,n_m = n_m + 1,n_{k^{'}v} = n_{k^{'}v} + 1,n_{k^{'}}=n_{k^{'}}+1
(c)增加计数nmk′=nmk′+1,nm=nm+1,nk′v=nk′v+1,nk′=nk′+1;
(
d
)
得到更新的两个计数矩阵
N
K
∗
V
=
[
n
k
v
]
和
N
M
∗
K
=
[
n
m
k
]
,
表示后验概率分布
p
(
z
∣
w
,
α
,
β
)
的样本计数
(d)得到更新的两个计数矩阵N_{K*V} = [n_{kv}] 和 N_{M*K} = [n_{mk}],表示后验概率分布p(z|w,\alpha,\beta)的样本计数
(d)得到更新的两个计数矩阵NK∗V=[nkv]和NM∗K=[nmk],表示后验概率分布p(z∣w,α,β)的样本计数;
利用得到的样本计数,计算模型参数
θ
m
k
=
n
m
k
+
α
k
∑
k
=
1
K
(
n
m
k
+
α
k
)
\theta_{mk} = \frac{n_{mk} + \alpha_k}{\sum_{k=1}^K(n_{mk}+\alpha_k)}
θmk=∑k=1K(nmk+αk)nmk+αk
φ
k
v
=
n
k
v
+
β
v
∑
v
=
1
K
(
n
k
v
+
β
v
)
\varphi_{kv} = \frac{n_{kv} + \beta_v}{\sum_{v=1}^K(n_{kv}+\beta_v)}
φkv=∑v=1K(nkv+βv)nkv+βv
def do_lda(text, words, alpha, beta, K, iters):
'''
潜在狄利克雷分配,采用收缩的吉布斯抽样算法估计模型的参数theta和phi
INPUT:
text - (list) 文本列表
words - (list) 单词列表
alpha - (list) 话题概率分布,模型超参数
beta - (list) 单词概率分布,模型超参数
K - (int) 设定的话题数
iters - (int) 设定的迭代次数
OUTPUT:
theta - (array) 话题的条件概率分布p(zk|dj),这里写成p(zk|dj)是为了和PLSA模型那一章的符号统一一下,方便对照着看
phi - (array) 单词的条件概率分布p(wi|zk)
'''
M = len(text) #文本数
V = len(words) #单词数
N_MK = np.zeros((M, K)) #文本-话题计数矩阵
N_KV = np.zeros((K, V)) #话题-单词计数矩阵
N_M = np.zeros(M) #文本计数向量
N_K = np.zeros(K) #话题计数向量
Z_MN = [] #用来保存每条文本的每个单词所在位置处抽样得到的话题
for m in range(M):
zm = []
t = text[m]
for n, w in enumerate(t):
v = words.index(w)
z = np.random.randint(K)
zm.append(z)
N_MK[m, z] += 1
N_M[m] += 1
N_KV[z, v] += 1
N_K[z] += 1
Z_MN.append(zm)
for i in range(iters):
print('{}/{}'.format(i+1, iters))
for m in range(M):
t = text[m]
for n, w in enumerate(t):
v = words.index(w)
z = Z_MN[m][n]
N_MK[m, z] -= 1
N_M[m] -= 1
N_KV[z][v] -= 1
N_K[z] -= 1
p = []
sums_k = 0
for k in range(K):
p_zk = (N_KV[k][v] + beta[v]) * (N_MK[m][k] + alpha[k])
sums_v = 0
sums_k += N_MK[m][k] + alpha[k]
for t in range(V):
sums_v += N_KV[k][t] + beta[t]
p_zk /= sums_v
p.append(p_zk)
p = p / sums_k
p = p / np.sum(p)
new_z = np.random.choice(a=K, p=p)
Z_MN[m][n] = new_z
N_MK[m, new_z] += 1
N_M[m] += 1
N_KV[new_z, v] += 1
N_K[new_z] += 1
theta = np.zeros((M, K))
phi = np.zeros((K, V))
for m in range(M):
sums_k = 0
for k in range(K):
theta[m, k] = N_MK[m][k] + alpha[k]
sums_k += theta[m, k]
theta[m] /= sums_k
for k in range(K):
sums_v = 0
for v in range(V):
phi[k, v] = N_KV[k][v] + beta[v]
sums_v += phi[k][v]
phi[k] /= sums_v
return theta, phi
iters = 10
theta, phi = do_lda(text, words, alpha, beta, K, iters) #LDA的吉布斯抽样
for k in range(K):
sort_inds = np.argsort(phi[k])[::-1]
topic = []
for i in range(10):
topic.append(words[sort_inds[i]])
topic = ' '.join(topic)
print('Topic {}: {}'.format(k+1, topic))