输入:
单词集合 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))