首页 » 机器学习实战 » 机器学习实战全文在线阅读

《机器学习实战》14.3 利用Python实现SVD

关灯直达底部

如果SVD确实那么好,那么该如何实现它呢?SVD实现了相关的线性代数,但这并不在本书的讨论范围之内。其实,有很多软件包可以实现SVD。NumPy有一个称为linalg的线性代数工具箱。接下来,我们了解一下如何利用该工具箱实现如下矩阵的SVD处理:

要在Python上实现该矩阵的SVD处理,请键入如下命令:

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

接下来就可以在如下多个矩阵上进行尝试:

>>> Uarray([[-0.14142136, -0.98994949],[-0.98994949, 0.14142136]])>>> Sigmaarray([ 10., 0.])>>> VTarray([[-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)>>> Sigmaarray([ 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应用的例子——推荐引擎。