資料預處理系列:(十二)用截斷奇異值分解降維
用截斷奇異值分解降維
截斷奇異值分解(Truncated singular value decomposition,TSVD)是一種矩陣因式分解(factorization)技術,將矩陣M分解成U,ΣΣ和V。它與PCA很像,只是SVD分解是在資料矩陣上進行,而PCA是在資料的協方差矩陣上進行。通常,SVD用於發現矩陣的主成份。
Getting ready
TSVD與一般SVD不同的是它可以產生一個指定維度的分解矩陣。例如,有一個n×n矩陣,通過SVD分解後仍然是一個n
這裡我們還用iris
資料集來演示TSVD:
from sklearn.datasets import load_iris iris = load_iris() iris_data = iris.data
How to do it...
TSVD物件的用法和其他物件類似。首先匯入需要的類,初始化,然後擬合:
In [5]:from sklearn.decomposition import TruncatedSVDIn [6]:
svdOut[6]:= TruncatedSVD(2) iris_transformed = svd.fit_transform(iris_data) iris_data[:5]
array([[ 5.1, 3.5, 1.4, 0.2], [ 4.9, 3. , 1.4, 0.2], [ 4.7, 3.2, 1.3, 0.2], [ 4.6, 3.1, 1.5, 0.2], [ 5. , 3.6, 1.4, 0.2]])In [7]:
iris_transformed[:5]
array([[ 5.91220352, -2.30344211], [ 5.57207573, -1.97383104], [ 5.4464847 , -2.09653267], [ 5.43601924, -1.87168085], [ 5.87506555, -2.32934799]])
最終結果如下圖所示:
In [10]:%matplotlib inline import matplotlib.pyplot as plt f = plt.figure(figsize=(5, 5)) ax = f.add_subplot(111) ax.scatter(iris_transformed[:, 0], iris_transformed[:, 1], c=iris.target) ax.set_title("Truncated SVD, 2 Components")Out[10]:
<matplotlib.text.Text at 0x8600be0>
How it works...
現在我們演示了scikit-learn的TruncatedSVD
模組,讓我們看看只用scipy
學習一些細節。
首先,我們用scipy
的linalg
處理SVD:
import numpy as np from scipy.linalg import svd D = np.array([[1, 2], [1, 3], [1, 4]]) DOut[12]:
array([[1, 2], [1, 3], [1, 4]])In [13]:
U, S, V = svd(D, full_matrices=False) U.shape, S.shape, V.shapeOut[13]:
((3, 2), (2,), (2, 2))
我們可以根據SVD的定義,用UU,SS和VV還原矩陣DD:
In [15]:np.diag(S)Out[15]:
array([[ 5.64015854, 0. ], [ 0. , 0.43429448]])In [16]:
np.dot(U.dot(np.diag(S)), V)Out[16]:
array([[ 1., 2.], [ 1., 3.], [ 1., 4.]])
TruncatedSVD
返回的矩陣是UU和SS的點積。如果我們想模擬TSVD,我們就去掉最新奇異值和對於UU的列向量。例如,我們想要一個主成份,可以這樣:
new_S = S[0] new_U = U[:, 0] new_U.dot(new_S)Out[17]:
array([-2.20719466, -3.16170819, -4.11622173])
一般情況下,如果我們想要截斷維度tt,那麼我們就去掉N−tN−t個奇異值。
There's more...
TruncatedSVD
還有一些細節需要注意。
符號翻轉(Sign flipping)
TruncatedSVD
有個“陷阱”。隨著隨機數生成器狀態的變化,TruncatedSVD
連續地擬合會改變輸出的符合。為了避免這個問題,建議只用TruncatedSVD
擬合一次,然後用其他變換。這正是管線命令的另一個用處。
要避免這種情況,可以這樣:
In [23]:tsvd = TruncatedSVD(2) tsvd.fit(iris_data) tsvd.transform(iris_data)[:5]Out[23]:
array([[ 5.91220352, -2.30344211], [ 5.57207573, -1.97383104], [ 5.4464847 , -2.09653267], [ 5.43601924, -1.87168085], [ 5.87506555, -2.32934799]])
稀疏矩陣
TruncatedSVD
相比PDA的一個優勢是TruncatedSVD
可以操作PDA處理不了的矩陣。這是因為PCA必須計算協方差矩陣,需要在整個矩陣上操作,如果矩陣太大,計算資源可能會不夠用。