复现经典:《统计学习方法》第17章 潜在语义分析
第17章 潛在語義分析
本文是李航老師的《統計學習方法》一書的代碼復現。作者:黃海廣
備注:代碼都可以在github中下載。我將陸續將代碼發布在公眾號“機器學習初學者”,可以在這個專輯在線閱讀。
1.單詞向量空間模型通過單詞的向量表示文本的語義內容。以單詞-文本矩陣為輸入,其中每一行對應一個單詞,每一列對應一個文本,每一個元素表示單詞在文本中的頻數或權值(如TF-IDF)
單詞向量空間模型認為,這個矩陣的每一列向量是單詞向量,表示一個文本,兩個單詞向量的內積或標準化內積表示文本之間的語義相似度。
2.話題向量空間模型通過話題的向量表示文本的語義內容。假設有話題文本矩陣
其中每一行對應一個話題,每一列對應一個文本每一個元素表示話題在文本中的權值。話題向量空間模型認為,這個矩陣的每一列向量是話題向量,表示一個文本,兩個話題向量的內積或標準化內積表示文本之間的語義相似度。假設有單詞話題矩陣其中每一行對應一個單詞,每一列對應一個話題,每一個元素表示單詞在話題中的權值。
給定一個單詞文本矩陣
潛在語義分析的目標是,找到合適的單詞-話題矩陣與話題文本矩陣,將單詞文本矩陣近似的表示為與的乘積形式。
等價地,潛在語義分析將文本在單詞向量空間的表示X通過線性變換轉換為話題向量空間中的表示。
潛在語義分析的關鍵是對單詞-文本矩陣進行以上的矩陣因子分解(話題分析)
3.潛在語義分析的算法是奇異值分解。通過對單詞文本矩陣進行截斷奇異值分解,得到
矩陣表示話題空間,矩陣是文本在話題空間的表示。
4.非負矩陣分解也可以用于話題分析。非負矩陣分解將非負的單詞文本矩陣近似分解成兩個非負矩陣和的乘積,得到
矩陣表示話題空間,矩陣是文本在話題空間的表示。
非負矩陣分解可以表為以下的最優化問題:
非負矩陣分解的算法是迭代算法。乘法更新規則的迭代算法,交替地對和進行更新。本質是梯度下降法,通過定義特殊的步長和非負的初始值,保證迭代過程及結果的矩陣和均為非負。
LSA 是一種無監督學習方法,主要用于文本的話題分析,其特點是通過矩陣分解發現文本與單詞之間的基于話題的語義關系。也稱為潛在語義索引(Latent semantic indexing, LSI)。
LSA 使用的是非概率的話題分析模型。將文本集合表示為單詞-文本矩陣,對單詞-文本矩陣進行奇異值分解,從而得到話題向量空間,以及文本在話題向量空間的表示。
非負矩陣分解(non-negative matrix factorization, NMF)是另一種矩陣的因子分解方法,其特點是分解的矩陣非負。
單詞向量空間
word vector space model
給定一個文本,用一個向量表示該文本的”語義“, 向量的每一維對應一個單詞,其數值為該單詞在該文本中出現的頻數或權值;基本假設是文本中所有單詞的出現情況表示了文本的語義內容,文本集合中的每個文本都表示為一個向量,存在于一個向量空間;向量空間的度量,如內積或標準化內積表示文本之間的相似度。
給定一個含有個文本的集合,以及在所有文本中出現的個單詞的集合. 將單詞在文本的出現的數據用一個單詞-文本矩陣(word-document matrix)表示,記作:
這是一個矩陣,元素表示單詞在文本中出現的頻數或權值。由于單詞的種類很多,而每個文本中出現單詞的種類通常較少,所有單詞-文本矩陣是一個稀疏矩陣。
權值通常用單詞頻率-逆文本率(term frequency-inverse document frequency, TF-IDF)表示:
,
其中,為單詞在文本中出現的概率,是逆文本率,用來衡量單詞對表示語義所起的重要性,
.
單詞向量空間模型的優點是模型簡單,計算效率高。因為單詞向量通常是稀疏的,單詞向量空間模型也有一定的局限性,體現在內積相似度未必能夠準確表達兩個文本的語義相似度上。因為自然語言的單詞具有一詞多義性(polysemy)及多詞一義性(synonymy)。
話題向量空間
1. 話題向量空間:
給定一個含有個文本的集合,以及在所有文本中出現的個單詞的集合. 可以獲得其單詞-文本矩陣:
假設所有文本共含有個話題。假設每個話題由一個定義在單詞集合上的維向量表示,稱為話題向量,即:
其中單詞在話題的權值,, 權值越大,該單詞在該話題中的重要程度就越高。這個話題向量 張成一個話題向量空間(topic vector space), 維數為.話題向量空間是單詞向量空間的一個子空間。
話題向量空間:
矩陣,稱為單詞-話題矩陣。
2. 文本在話題向量空間中的表示 ?:
考慮文本集合的文本, 在單詞向量空間中由一個向量表示,將投影到話題向量空間中,得到話題向量空間的一個向量, 是一個維向量:
其中,是文本在話題中的權值, , 權值越大,該話題在該文本中的重要程度就越高。
矩陣 表示話題在文本中出現的情況,稱為話題-文本矩陣(topic-document matrix),記作:
也可寫成:
3. 從單詞向量空間到話題向量空間的線性變換:
如此,單詞向量空間的文本向量可以通過他在話題空間中的向量近似表示,具體地由個話題向量以為系數的線性組合近似表示:
所以,單詞-文本矩陣可以近似的表示為單詞-話題矩陣與話題-文本矩陣的乘積形式。
直觀上,潛在語義分析是將單詞向量空間的表示通過線性變換轉換為在話題向量空間中的表示。這個線性變換由矩陣因子分解式的形式體現。
潛在語義分析算法
潛在語義分析利用矩陣奇異值分解,具體地,對單詞-文本矩陣進行奇異值分解,將其左矩陣作為話題向量空間,將其對角矩陣與右矩陣的乘積作為文本在話題向量空間的表示。
給定一個含有個文本的集合,以及在所有文本中出現的個單詞的集合. 可以獲得其單詞-文本矩陣:
截斷奇異值分解:
潛在語義分析根據確定的話題數對單詞-文本矩陣進行截斷奇異值分解:
矩陣的每一個列向量 表示一個話題,稱為話題向量。由這 個話題向量張成一個子空間:
稱為話題向量空間。
綜上, 可以通過對單詞-文本矩陣的奇異值分解進行潛在語義分析:
得到話題空間 , 以及文本在話題空間的表示().
非負矩陣分解算法
非負矩陣分解也可以用于話題分析。對單詞-文本矩陣進行非負矩陣分解,將其左矩陣作為話題向量空間,將其右矩陣作為文本在話題向量空間的表示。
非負矩陣分解
若一個矩陣的索引元素非負,則該矩陣為非負矩陣。若是非負矩陣,則:.
給定一個非負矩陣, 找到兩個非負矩陣 和 , 使得:
即非負矩陣分解為兩個非負矩陣和的乘積形式,成為非負矩陣分解。因為與完全相等很難實現,所以只要求近似相等。
假設非負矩陣是矩陣,非負矩陣和分別為 矩陣和 矩陣。假設 即 和 小于原矩陣 , 所以非負矩陣分解是對原數據的壓縮。
稱 為基矩陣, 為系數矩陣。非負矩陣分解旨在用較少的基向量,系數向量來表示為較大的數據矩陣。
令
為話題向量空間, 表示文本集合的 個話題, 令為文本在話題向量空間的表示, 表示文本集合的 個文本。算法
非負矩陣分解可以形式化為最優化問題求解。可以利用平方損失或散度來作為損失函數。
目標函數 關于 和 的最小化,滿足約束條件 , 即:
乘法更新規則:
?(17.33)
?(17.34)
選擇初始矩陣 和 為非負矩陣,可以保證迭代過程及結果的矩陣 和 非負。
算法 17.1 (非負矩陣分解的迭代算法)
輸入:單詞-文本矩陣 , 文本集合的話題個數 , 最大迭代次數 ;
輸出:話題矩陣 , 文本表示矩陣 。
1). 初始化
, 并對 的每一列數據歸一化;
;
2). 迭代
對迭代次數由1到執行下列步驟:
a. 更新的元素,對 從1到 從1到按(17.33)更新 ;
a. 更新的元素,對 從1到 從1到按(17.34)更新 ;
圖例 17.1
import?numpy?as?np from?sklearn.decomposition?import?TruncatedSVD X?=?[[2,?0,?0,?0],?[0,?2,?0,?0],?[0,?0,?1,?0],?[0,?0,?2,?3],?[0,?0,?0,?1],?[1,?2,?2,?1]] X?=?np.asarray(X);X array([[2, 0, 0, 0],[0, 2, 0, 0],[0, 0, 1, 0],[0, 0, 2, 3],[0, 0, 0, 1],[1, 2, 2, 1]]) #?奇異值分解 U,sigma,VT=np.linalg.svd(X) U array([[-7.84368672e-02, -2.84423033e-01, 8.94427191e-01,-2.15138396e-01, -6.45002451e-02, -2.50012770e-01],[-1.56873734e-01, -5.68846066e-01, -4.47213595e-01,-4.30276793e-01, -1.29000490e-01, -5.00025540e-01],[-1.42622354e-01, 1.37930417e-02, -1.25029761e-16,6.53519444e-01, 3.88575115e-01, -6.33553733e-01],[-7.28804669e-01, 5.53499910e-01, -2.24565656e-16,-1.56161345e-01, -3.23288048e-01, -1.83248673e-01],[-1.47853320e-01, 1.75304609e-01, 8.49795536e-18,-4.87733411e-01, 8.40863653e-01, 4.97204799e-02],[-6.29190197e-01, -5.08166890e-01, -1.60733896e-16,2.81459486e-01, 1.29000490e-01, 5.00025540e-01]]) sigma array([4.47696617, 2.7519661 , 2. , 1.17620428]) VT array([[-1.75579600e-01, -3.51159201e-01, -6.38515454e-01,-6.61934313e-01],[-3.91361272e-01, -7.82722545e-01, 3.79579831e-02,4.82432341e-01],[ 8.94427191e-01, -4.47213595e-01, -2.23998094e-16,5.45344065e-17],[-1.26523351e-01, -2.53046702e-01, 7.68672366e-01,-5.73674125e-01]]) #?截斷奇異值分解svd?=?TruncatedSVD(n_components=3,?n_iter=7,?random_state=42) svd.fit(X)?? TruncatedSVD(algorithm='randomized', n_components=3, n_iter=7, random_state=42,tol=0.0) print(svd.explained_variance_ratio_) [0.39945801 0.34585056 0.18861789] print(svd.explained_variance_ratio_.sum()) 0.933926460028446 print(svd.singular_values_) [4.47696617 2.7519661 2. ]非負矩陣分解
def?inverse_transform(W,?H):#?重構return?W.dot(H)def?loss(X,?X_):#計算重構誤差return?((X?-?X_)?*?(X?-?X_)).sum() #?算法?17.1class?MyNMF:def?fit(self,?X,?k,?t):m,?n?=?X.shapeW?=?np.random.rand(m,?k)W?=?W/W.sum(axis=0)H?=?np.random.rand(k,?n)i?=?1while?i?<?t:W?=?W?*?X.dot(H.T)?/?W.dot(H).dot(H.T)H?=?H?*?(W.T).dot(X)?/?(W.T).dot(W).dot(H)i?+=?1return?W,?H model?=?MyNMF() W,?H?=?model.fit(X,?3,?200) W array([[0.00000000e+00, 4.27327705e-01, 6.30117924e-27],[5.11680721e-97, 8.57828102e-01, 0.00000000e+00],[2.97520805e-88, 2.39454414e-18, 4.36332453e-01],[2.15653741e+00, 3.38756557e-21, 8.38350315e-01],[7.36106818e-01, 1.00339294e-54, 8.72892573e-38],[6.78344810e-01, 1.07009504e+00, 8.57259947e-01]]) H array([[7.14647214e-10, 1.01233436e-03, 3.76097657e-02, 1.35755597e+00],[9.30509415e-01, 1.86788842e+00, 1.16682319e-02, 4.54479182e-03],[4.95440453e-03, 6.18432747e-04, 2.28890170e+00, 8.61836630e-02]]) #?重構 X_?=?inverse_transform(W,?H);X_ array([[3.97632453e-01, 7.98200474e-01, 4.98615876e-03, 1.94211546e-03],[7.98217125e-01, 1.60232718e+00, 1.00093372e-02, 3.89865014e-03],[2.16176748e-03, 2.69842277e-04, 9.98722093e-01, 3.76047290e-02],[4.15352814e-03, 2.70160021e-03, 2.00000833e+00, 2.99987233e+00],[5.26056687e-10, 7.45186228e-04, 2.76848049e-02, 9.99306203e-01],[9.99980721e-01, 2.00003500e+00, 2.00018226e+00, 9.99636205e-01]]) #?重構誤差loss(X,?X_) 4.002356735601103使用 sklearn 計算
from?sklearn.decomposition?import?NMF model?=?NMF(n_components=3,?init='random',?max_iter=200,?random_state=0) W?=?model.fit_transform(X) H?=?model.components_ W array([[0. , 0.53849498, 0. ],[0. , 1.07698996, 0. ],[0.69891361, 0. , 0. ],[1.39782972, 0. , 1.97173859],[0. , 0. , 0.65783848],[1.39783002, 1.34623756, 0.65573258]]) H array([[0.00000000e+00, 0.00000000e+00, 1.43078959e+00, 1.71761682e-03],[7.42810976e-01, 1.48562195e+00, 0.00000000e+00, 3.30264644e-04],[0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 1.52030365e+00]]) X__?=?inverse_transform(W,?H);X__ array([[3.99999983e-01, 7.99999966e-01, 0.00000000e+00, 1.77845853e-04],[7.99999966e-01, 1.59999993e+00, 0.00000000e+00, 3.55691707e-04],[0.00000000e+00, 0.00000000e+00, 9.99998311e-01, 1.20046577e-03],[0.00000000e+00, 0.00000000e+00, 2.00000021e+00, 3.00004230e+00],[0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 1.00011424e+00],[1.00000003e+00, 2.00000007e+00, 2.00000064e+00, 9.99758185e-01]]) loss(X,?X__) 4.000001672582457本章代碼來源: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] ?火燙火燙的: https://blog.csdn.net/tudaodiaozhale
[7] ?hktxt: https://github.com/hktxt/Learn-Statistical-Learning-Method
總結
以上是生活随笔為你收集整理的复现经典:《统计学习方法》第17章 潜在语义分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 首发:李航老师的《统计学习方法》第二版的
- 下一篇: 复现经典:《统计学习方法》第16章 主