天天看點

複現經典:《統計學習方法》第18章 機率潛在語義分析

第18章 機率潛在語義分析

本文是李航老師的《統計學習方法》一書的代碼複現。作者:黃海廣

備注:代碼都可以在github中下載下傳。我将陸續将代碼釋出在公衆号“機器學習初學者”,可以在這個專輯線上閱讀。

1.機率潛在語義分析是利用機率生成模型對文本集合進行話題分析的方法。機率潛在語義分析受潛在語義分析的啟發提出兩者可以通過矩陣分解關聯起來。

給定一個文本集合,通過機率潛在語義分析,可以得到各個文本生成話題的條件機率分布,以及各個話題生成單詞的條件機率分布。

機率潛在語義分析的模型有生成模型,以及等價的共現模型。其學習政策是觀測資料的極大似然估計,其學習算法是EM算法。

2.生成模型表示文本生成話題,話題生成單詞進而得到單詞文本共現資料的過程;假設每個文本由一個話題分布決定,每個話題由一個單詞分布決定。單詞變量

與文本變量

是觀測變量話題變量

是隐變量。生成模型的定義如下:

3.共現模型描述文本單詞共現資料擁有的模式。共現模型的定義如下:

4.機率潛在語義分析的模型的參數個數是

。現實中

,是以機率潛在語義分析通過話題對資料進行了更簡潔地表示,實作了資料壓縮。

5.模型中的機率分布

可以由參數空間中的單純形表示。

維參數空間中,單詞單純形表示所有可能的文本的分布,在其中的話題單純形表示在

個話題定義下的所有可能的文本的分布。話題單純形是單詞單純形的子集,表示潛在語義空間。

6.機率潛在語義分析的學習通常采用EM算法通過疊代學習模型的參數,

,而

可直接統計得出。

機率潛在語義分析(probabilistic latent semantic analysis, PLSA),也稱機率潛在語義索引(probabilistic latent semantic indexing, PLSI),是一種利用機率生成模型對文本集合進行話題分析的無監督學習方法。

模型最大特點是用隐變量表示話題,整個模型表示文本生成話題,話題生成單詞,進而得到單詞-文本共現資料的過程;假設每個文本由一個話題分布決定,每個話題由一個單詞分布決定。

18.1.2 生成模型

假設有單詞集合

{

}, 其中M是單詞個數;文本(名額)集合

{

}, 其中N是文本個數;話題集合

{

},其中

是預先設定的話題個數。随機變量

取值于單詞集合;随機變量

取值于文本集合,随機變量

取值于話題集合。機率分布

、條件機率分布

、條件機率分布

皆屬于多項分布,其中

表示生成文本

的機率,

表示文本

生成話題

的機率,

表示話題

生成單詞

每個文本

擁有自己的話題機率分布

,每個話題

擁有自己的單詞機率分布

;也就是說一個文本的内容由其相關話題決定,一個話題的内容由其相關單詞決定。

生成模型通過以下步驟生成文本·單詞共現資料:

(1)依據機率分布

,從文本(名額)集合中随機選取一個文本

, 共生成

 個文本;針對每個文本,執行以下操作;

(2)在文本

給定條件下,依據條件機率分布

, 從話題集合随機選取一個話題

, 共生成

個話題,這裡

是文本長度;

(3)在話題

給定條件下,依據條件機率分布

, 從單詞集合中随機選取一個單詞

.

注意這裡為叙述友善,假設文本都是等長的,現實中不需要這個假設。

生成模型中, 單詞變量

與文本變量

是觀測變量, 話題變量

是隐變量, 也就是說模型生成的是單詞-話題-文本三元組合 (

)的集合, 但觀測到的單詞-文本二進制組 (

)的集合, 觀測資料表示為單詞-文本矩陣

的形式,矩陣

的行表示單詞,清單示文本, 元素表示單詞-文本對(

)的出現次數。

從資料的生成過程可以推出,文本-單詞共現資料

的生成機率為所有單詞-文本對(

)的生成機率的乘積:

這裡

表示 (

)的出現次數,單詞-文本對出現的總次數是

。每個單詞-文本對(

)的生成機率由一下公式決定:

18.1.3 共現模型

雖然生成模型與共現模型在機率公式意義上是等價的,但是擁有不同的性質。生成模型刻畫文本-單詞共現資料生成的過程,共現模型描述文本-單詞共現資料擁有的模式。

如果直接定義單詞與文本的共現機率

, 模型參數的個數是

, 其中

是單詞數,

是文本數。機率潛在語義分析的生成模型和共現模型的參數個數是

, 其中

算法 18.1 (機率潛在語義模型參數估計的EM算法)

輸入:設單詞集合為

{

}, 文本集合為

{

}, 話題集合為

{

}, 共現資料

輸出:

.

  1. 設定參數

  2. 疊代執行以下E步,M步,直到收斂為止。

E步:

M步:

習題 18.3

import numpy as np      
X = [[0,0,1,1,0,0,0,0,0], 
     [0,0,0,0,0,1,0,0,1], 
     [0,1,0,0,0,0,0,1,0], 
     [0,0,0,0,0,0,1,0,1], 
     [1,0,0,0,0,1,0,0,0], 
     [1,1,1,1,1,1,1,1,1], 
     [1,0,1,0,0,0,0,0,0], 
     [0,0,0,0,0,0,1,0,1], 
     [0,0,0,0,0,2,0,0,1], 
     [1,0,1,0,0,0,0,1,0], 
     [0,0,0,1,1,0,0,0,0]]
X = np.asarray(X);X      
array([[0, 0, 1, 1, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 1, 0, 0, 1],
       [0, 1, 0, 0, 0, 0, 0, 1, 0],
       [0, 0, 0, 0, 0, 0, 1, 0, 1],
       [1, 0, 0, 0, 0, 1, 0, 0, 0],
       [1, 1, 1, 1, 1, 1, 1, 1, 1],
       [1, 0, 1, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 1, 0, 1],
       [0, 0, 0, 0, 0, 2, 0, 0, 1],
       [1, 0, 1, 0, 0, 0, 0, 1, 0],
       [0, 0, 0, 1, 1, 0, 0, 0, 0]])      
X.shape      
(11, 9)      
X = X.T;X      
array([[0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0],
       [0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0],
       [1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0],
       [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
       [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
       [0, 1, 0, 0, 1, 1, 0, 0, 2, 0, 0],
       [0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0],
       [0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0],
       [0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0]])      
class PLSA:
    def __init__(self, K, max_iter):
        self.K = K
        self.max_iter = max_iter

    def fit(self, X):
        n_d, n_w = X.shape

        # P(z|w,d)
        p_z_dw = np.zeros((n_d, n_w, self.K))

        # P(z|d)
        p_z_d = np.random.rand(n_d, self.K)

        # P(w|z)
        p_w_z = np.random.rand(self.K, n_w)

        for i_iter in range(self.max_iter):
            # E step
            for di in range(n_d):
                for wi in range(n_w):
                    sum_zk = np.zeros((self.K))
                    for zi in range(self.K):
                        sum_zk[zi] = p_z_d[di, zi] * p_w_z[zi, wi]
                    sum1 = np.sum(sum_zk)
                    if sum1 == 0:
                        sum1 = 1
                    for zi in range(self.K):
                        p_z_dw[di, wi, zi] = sum_zk[zi] / sum1

            # M step

            # update P(z|d)
            for di in range(n_d):
                for zi in range(self.K):
                    sum1 = 0.
                    sum2 = 0.

                    for wi in range(n_w):
                        sum1 = sum1 + X[di, wi] * p_z_dw[di, wi, zi]
                        sum2 = sum2 + X[di, wi]

                    if sum2 == 0:
                        sum2 = 1
                    p_z_d[di, zi] = sum1 / sum2

            # update P(w|z)
            for zi in range(self.K):
                sum2 = np.zeros((n_w))
                for wi in range(n_w):
                    for di in range(n_d):
                        sum2[wi] = sum2[wi] + X[di, wi] * p_z_dw[di, wi, zi]
                sum1 = np.sum(sum2)
                if sum1 == 0:
                    sum1 = 1
                    for wi in range(n_w):
                        p_w_z[zi, wi] = sum2[wi] / sum1

        return p_w_z, p_z_d


# https://github.com/lipiji/PG_PLSA/blob/master/plsa.py      
model = PLSA(2, 100)
p_w_z, p_z_d = model.fit(X)      
p_w_z      
array([[0.64238757, 0.05486094, 0.18905573, 0.24047994, 0.41230822,
        0.38136674, 0.81525232, 0.74314243, 0.32465342, 0.19798429,
        0.72010476],
       [0.6337431 , 0.79442181, 0.96755364, 0.22924392, 0.99367301,
        0.20277986, 0.40513752, 0.51164374, 0.73750246, 0.22300907,
        0.17339099]])      
p_z_d      
array([[7.14884177e-01, 2.85115823e-01],
       [5.38307075e-02, 9.46169293e-01],
       [1.00000000e+00, 3.40624611e-11],
       [1.00000000e+00, 1.12459358e-24],
       [1.00000000e+00, 5.00831891e-42],
       [1.66511004e-19, 1.00000000e+00],
       [1.00000000e+00, 8.02144289e-15],
       [1.04149223e-02, 9.89585078e-01],
       [5.96793031e-03, 9.94032070e-01]])      

本章代碼來源:https://github.com/hktxt/Learn-Statistical-Learning-Method

下載下傳位址

​​https://github.com/fengdu78/lihang-code​​

參考資料:

[1] 《統計學習方法》: https://baike.baidu.com/item/統計學習方法/10430179

[2] 黃海廣: https://github.com/fengdu78

[3]  github: https://github.com/fengdu78/lihang-code

[4]  wzyonggege: https://github.com/wzyonggege/statistical-learning-method

[5]  WenDesi: https://github.com/WenDesi/lihang_book_algorithm

[6]  火燙火燙的