潜在狄利克雷分配(Latent Dirichlet Allocation,LDA)—无监督学习方法、概率模型、生成模型、线性模型、非参数化模型、贝叶斯学习、批量学习

定义

输入:

          单词集合 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(zwm)决定,zZ。分布p(zwm)服从多项分布(严格意义上类别分布)

              , 其参数为 θ 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,φkDir(β),作为话题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,θmDir(α),作为文本wm的话题分布p(zwm),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(n1,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,zmnMult(θ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,ωmnMult(φ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=1kθiαi1,i=1kαi=1,θi0,i=1,2,,k,Γ(s)=0xs1exdx,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=zkMult(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=nmk1,nm=nm1,nkv=nkv1,nk=nk1;

( 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(zizi,w,α,β)v=1V(nkv+βv)nkv+βvk=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,nkv=nkv+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)得到更新的两个计数矩阵NKV=[nkv]NMK=[nmk],表示后验概率分布p(zw,α,β)的样本计数;

利用得到的样本计数,计算模型参数

θ 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))

你可能感兴趣的:(Artificial,Intelligence,人工智能,机器学习,潜在狄利克雷分配,LDA)