讀古今文學網 > 機器學習實戰 > 14.3 利用Python實現SVD >

14.3 利用Python實現SVD

如果SVD確實那麼好,那麼該如何實現它呢?SVD實現了相關的線性代數,但這並不在本書的討論範圍之內。其實,有很多軟件包可以實現SVD。NumPy有一個稱為linalg的線性代數工具箱。接下來,我們瞭解一下如何利用該工具箱實現如下矩陣的SVD處理:

要在Python上實現該矩陣的SVD處理,請鍵入如下命令:

>>> from numpy import *
>>> U,Sigma,VT=linalg.svd([[1, 1],[7, 7]])
  

接下來就可以在如下多個矩陣上進行嘗試:

>>> U
array([[-0.14142136, -0.98994949],
[-0.98994949, 0.14142136]])
>>> Sigma
array([ 10., 0.])
>>> VT
array([[-0.70710678, -0.70710678],
[-0.70710678, 0.70710678]])
  

我們注意到,矩陣Sigma以行向量array([ 10., 0.])返回,而非如下矩陣:

array([[ 10., 0.],
       [ 0., 0.]]). 
  

由於矩陣除了對角元素其他均為0,因此這種僅返回對角元素的方式能夠節省空間,這就是由NumPy的內部機制產生的。我們所要記住的是,一旦看到Sigma就要知道它是一個矩陣。好了,接下來我們將在一個更大的數據集上進行更多的分解。

建立一個新文件svdRec.py並加入如下代碼:

def loadExData:
return[[1, 1, 1, 0, 0],
       [2, 2, 2, 0, 0],
       [1, 1, 1, 0, 0],
       [5, 5, 5, 0, 0],
       [1, 1, 0, 2, 2],
       [0, 0, 0, 3, 3],
       [0, 0, 0, 1, 1]]  
  

接下來我們對該矩陣進行SVD分解。在保存好文件svdRec.py之後,我們在Python提示符下輸入:

>>> import svdRec
>>> Data=svdRec.loadExData
>>> U,Sigma,VT=linalg.svd(Data)
>>> Sigma
array([ 9.72140007e+00, 5.29397912e+00, 6.84226362e-01,7.16251492e-16, 4.85169600e-32])
  

前3個數值比其他的值大了很多(如果你的最後兩個值的結果與這裡的結果稍有不同,也不必擔心。它們太小了,所以在不同機器上產生的結果就可能會稍有不同,但是數量級應該和這裡的結果差不多)。於是,我們就可以將最後兩個值去掉了。

接下來,我們的原始數據集就可以用如下結果來近似:

圖14-2就是上述近似計算的一個示意圖。

圖14-2 SVD的示意圖。矩陣Data被分解。淺灰色區域是原始數據,深灰色區域是矩陣近似計算僅需要的數據

我們試圖重構原始矩陣。首先構建一個3×3的矩陣Sig3

>>> Sig3=mat([[Sigma[0], 0, 0],[0, Sigma[1], 0], [0, 0, Sigma[2]]])
  

接下來我們重構原始矩陣的近似矩陣。由於Sig3僅為3x3矩陣,我們只需使用矩陣U的前3列和VT的前3行。在Python中實現這一點,輸入命令:

>>> U[:,:3]*Sig3*VT[:3,:]
array([[ 1.,   1.,   1.,   0.,   0.  ],
       [ 2.,   2.,   2.,   -0.,  -0. ],
       [ 1.,   1.,   1.,   -0.,  -0. ],
       [ 5.,   5.,   5.,   0.,    0. ],
       [ 1.,   1.,   -0.,   2.,   2. ],
       [ 0.,   0.,   -0.,   3.,   3. ],
            [ 0.,   0.,   -0.,   1.,   1.  ]])
  

我們是如何知道僅需保留前3個奇異值的呢?確定要保留的奇異值的數目有很多啟髮式的策略,其中一個典型的做法就是保留矩陣中90%的能量信息。為了計算總能量信息,我們將所有的奇異值求其平方和。於是可以將奇異值的平方和累加到總值的90%為止。另一個啟髮式策略就是,當矩陣上有上萬的奇異值時,那麼就保留前面的2000或3000個。儘管後一種方法不太優雅,但是在實際中更容易實施。之所以說它不夠優雅,就是因為在任何數據集上都不能保證前3000個奇異值就能夠包含90%的能量信息。但在通常情況下,使用者往往都對數據有足夠的瞭解,從而就能夠做出類似的假設了。

現在我們已經通過三個矩陣對原始矩陣進行了近似。我們可以用一個小很多的矩陣來表示一個大矩陣。有很多應用可以通過SVD來提升性能。下面我們將討論一個比較流行的SVD應用的例子——推薦引擎。