矩阵SVD在机器学习中的应用

本篇整理了一些SVD奇异值分解在机器学习中的应用:

  • SVD奇异值分解
  • SVD在推荐算法中的应用
  • PCD 数据降维
  • 一个图片处理的例子

SVD奇异值分解

讲svd之前,先了解一下特征向理和特征值的概念。

对于一个方阵M,如果有向量v 和 数值 λ ,Mv = λv,则 v 称为 M 的对应于特征值 λ 的特征向量。

 

特征分解: 方阵M可以被分解为 M =Q∗Λ∗Q−1 QΛQ1QΛQ1

其中QN×N方阵,由特征向量组成的矩阵,且其第 i 列为 M 的第i个特征向量 。 Λ 是对角矩阵,其对角线上的元素为对应的特征值。

 

SVD奇异值分解和特征分解很像,区别就是此时Data 是一个m * n的矩阵,不是方阵。

矩阵Data可被分解为三个矩阵

  ΣVT就分别是m* m、m*n和n*n。Σ为对角矩阵,对角元素称为奇异值。

SVD特征分解的关系:

Data * DataT 是个方阵,特征分解可得  Data * DataT  = U mxm *Σ1* UT mxm 

DataT * Data  是个方阵,特征分解可得 DataT * Data = V nxn *Σ2* VTnxn

svd 分解中 U mxm 就是Data * DataT 的特征向量,V nxn 就是DataT * Data 的特征向量Σ Data * DataT 特征值Σ1的平方根。

SVD的几个特性

1:取特征值的前K个项,可以近似的表示矩阵Data。

2:取特征值的前k项,Vnxk可以表示为

SVD在推荐算法中的应用

在推荐算法中,根据用户和用户之间的相似度,就可以向用户推荐另一个用户没有选择的物品。

根据物品和物品之间的相似度,就可以向选择该物品的用户推荐另一种物品。相似度计算有 《欧氏距离》,《皮尔逊相关系数》,《余弦相似度》等一系列算法。

在实际的应用中,由于商品和人的数量比较多,相似度计算的复杂度比较高,推荐效果可能也不好。

更先进的方法利用SVD从数据中构建一个低维的空间,然后再在该低维空间下计算其相似度。

假设有一个矩阵,列表示用户 ,行表示商品。由此主成了一个矩阵,矩阵的值表示该用户对商品的评分,0表示未评分。

对该矩阵svd 分解以后

U =
   -0.4472   -0.5373   -0.0064   -0.5037   -0.3857   -0.3298
   -0.3586    0.2461    0.8622   -0.1458    0.0780    0.2002
   -0.2925   -0.4033   -0.2275   -0.1038    0.4360    0.7065
   -0.2078    0.6700   -0.3951   -0.5888    0.0260    0.0667
   -0.5099    0.0597   -0.1097    0.2869    0.5946   -0.5371
   -0.5316    0.1887   -0.1914    0.5341   -0.5485    0.2429

S =
   17.7139         0         0         0
         0    6.3917         0         0
         0         0    3.0980         0
         0         0         0    1.3290
         0         0         0         0
         0         0         0         0

V =
   -0.5710   -0.2228    0.6749    0.4109
   -0.4275   -0.5172   -0.6929    0.2637
   -0.3846    0.8246   -0.2532    0.3286
   -0.5859    0.0532    0.0140   -0.8085

 矩阵 U 的每一行,反映的是每一个商品的特征。矩阵 V 的每一行,反映的是每一个用户的特征。

  保留2个维度的的特征,再对三个矩阵相乘。可以得到原始近似值

 U(1:6,1:2) * S(1:2,1:2) * V(1:4,1:2)' 得到的新矩阵和原始矩阵相似。

 这个就是前面提到的svd特性1,但这个不是我们在推荐系统中要用到的特性,接下来的图片处理的例子将用到这个特性。

    5.2885    5.1627    0.2149    4.4591
    3.2768    1.9021    3.7400    3.8058
    3.5324    3.5479   -0.1332    2.8984
    1.1475   -0.6417    4.9472    2.3846
    5.0727    3.6640    3.7887    5.3130
    5.1086    3.4019    4.6166    5.5822

 为了更形象的描述 特征 矩阵能反映出商品和用户 的特征。把前面保留2个维度的 U,V 矩阵列 表示在 一张二维图上。

从图中Ben 和 Fred 在差不多的位置上, 对比原始矩阵 Ben 和 Fred的评分数据也是比较相似。

s5,s6 也在差不多的位置上,对比原始矩阵它们的评分也基本相近。

所以,保留2个维度的特征,同样可以反映出原始数据的基本特性。利用这个思想,取前K个维度的特征进行相似度计算可以大大的减少运算复杂度。(K 值怎么定?一个典型的做法就是计算出保留矩阵中90%的能量信息所需要的K值。这里不作进述)

假设一个新用户bob ,他的评分数据为[5,5,0,0,0,5]。我们现在要对他作出个性推荐。利用前面的svd特性2,计算出bob 用户特征 Vbob

 

标进原来的坐标图,

根据《余弦相似度》计算的话——看夹角,应该是和ben最相似。

观察ben的评分向量为:【5 5 3 0 5 5】。

对比Bob的评分向量:【5 5 0 0 0 5】。

然后找出ben评分过而Bob未评分的item,并按分值排序,即可推荐【season 5,season 3】。

这个就是基于用户推荐的思想。当然也可以使用 U,来计算基于商品的推荐。

svd 在里面的关键作用是:

1:自动帮我们划分出基于用户 的特征,和基于商品的特征。

2:在上面的基础上,选取一个维度K。使用我们可以在一个低维空间下计算相似度,降低运算复杂度。

 

PCA 数据降维

Principal Component Analysis 主成份分析,这个是机器学习常用的数据降维方法。

为什么要数据降维?在机器学习的算法训练中,我们可能有大量的冗余的特征。这些特征不一定要训练中能起到很好的作用,相反可能在存储成本和计算量上都比较大。

pca 的作用就是保留主要的特征维度,去掉不必要的特征,更加有效的提高和优化我们的学习算法。

这个篇幅,则以吴恩达机器学习公开课中 一个图片pca的例子来介绍。

pca算法原理

假设现在一个二维的训练数据,打印出来是图中的效果。如果想找出一条线来反映这些数据的最主要形态,那就是红的标记这个方向。

如果所有的数据,往这个方向上投影,那么产生一个一维的数据,如右图的红点,它能反映出训练数据的最主要形态,训练样本之间有最大方差。此时的训练数据的特征更明显。

如果是另一方向,所有的数据将会挤在一起,方差变的最小,不能反映训练数据的主要特征。

训练数据会有多维的特征,如果分别向多个主要特征的方向上投影,最终将得一个低维度的训练数据集。在这个低维度的训练数据集中,特征更加精准。

这就是pca的思想。

那么,如果找出主要的特征方向呢。训练数据的 协方差矩阵 的特征向量就是我们要找的特征方向。

 

PCA 算法步骤,octave 代码

 

先展示100张人脸,训练数据是32*32的灰度图片

 

displayData(X(1:100, :));

 

1:训练数据处理,归一化。

 

[X_norm, mu, sigma] = featureNormalize(X);

 

function [X_norm, mu, sigma] = featureNormalize(X)
%FEATURENORMALIZE Normalizes the features in X 
%   FEATURENORMALIZE(X) returns a normalized version of X where
%   the mean value of each feature is 0 and the standard deviation
%   is 1. This is often a good preprocessing step to do when
%   working with learning algorithms.

mu = mean(X);
X_norm = bsxfun(@minus, X, mu);

sigma = std(X_norm);
X_norm = bsxfun(@rdivide, X_norm, sigma);


% ============================================================

end

 2:计算协方差矩阵,计算协方差矩阵的特征值

[U, S] = pca(X_norm);

 

function [U, S] = pca(X)
%PCA Run principal component analysis on the dataset X
%   [U, S, X] = pca(X) computes eigenvectors of the covariance matrix of X
%   Returns the eigenvectors U, the eigenvalues (on diagonal) in S
%

% Useful values
[m, n] = size(X);

% You need to return the following variables correctly.
U = zeros(n);
S = zeros(n);

% ====================== YOUR CODE HERE ======================
% Instructions: You should first compute the covariance matrix. Then, you
%               should use the "svd" function to compute the eigenvectors
%               and eigenvalues of the covariance matrix. 
%
% Note: When computing the covariance matrix, remember to divide by m (the
%       number of examples).
%

Sigma = (1/m) *(X'*X);

[U, S, V] = svd(Sigma);



% =========================================================================

end

 

注:这里用的协方差矩阵求的svd ,根据前面讲的svd和特征分解的关系,其实可以直接用X_norm 求svd 得到 V 即为协方差矩阵svd 的U。

 

 展示一下前面求的均值mu,一张大众脸。我靠。

 展示下特征U,每张都一个脸轮廓。

displayData(U(:, 1:36)');

 

3:选取K个维度的特征进行PCA降维。K的选取有公式,这里不阐述。

K = 100;
Z = projectData(X_norm, U, K)

 

function Z = projectData(X, U, K)
%PROJECTDATA Computes the reduced data representation when projecting only 
%on to the top k eigenvectors
%   Z = projectData(X, U, K) computes the projection of 
%   the normalized inputs X into the reduced dimensional space spanned by
%   the first K columns of U. It returns the projected examples in Z.
%

% You need to return the following variables correctly.
Z = zeros(size(X, 1), K);

% ====================== YOUR CODE HERE ======================
% Instructions: Compute the projection of the data using only the top K 
%               eigenvectors in U (first K columns). 
%               For the i-th example X(i,:), the projection on to the k-th 
%               eigenvector is given as follows:
%                    x = X(i, :)';
%                    projection_k = x' * U(:, k);
%


Z = X*U(:,1:K);

% =============================================================

end

 展示降维的效果,黑黑一片。原来的图片是32*32像素值,现在只有100像素值

displayData(Z(1:100,:));

 

4:复原图片

K = 100;
X_rec  = recoverData(Z, U, K);

 

function X_rec = recoverData(Z, U, K)
%RECOVERDATA Recovers an approximation of the original data when using the 
%projected data
%   X_rec = RECOVERDATA(Z, U, K) recovers an approximation the 
%   original data that has been reduced to K dimensions. It returns the
%   approximate reconstruction in X_rec.
%

% You need to return the following variables correctly.
X_rec = zeros(size(Z, 1), size(U, 1));

% ====================== YOUR CODE HERE ======================
% Instructions: Compute the approximation of the data by projecting back
%               onto the original space using the top K eigenvectors in U.
%
%               For the i-th example Z(i,:), the (approximate)
%               recovered data for dimension j is given as follows:
%                    v = Z(i, :)';
%                    recovered_j = v' * U(j, 1:K)';
%
%               Notice that U(j, 1:K) is a row vector.
%               

X_rec = Z*(U(:,1:K)');

% =============================================================

end

 复原后的效果,是不是看上去没什么区别。

% Display normalized data
subplot(1, 2, 1);
displayData(X_norm(1:100,:));

 

 一个图片处理的例子

前面提到的 svd 的第一个特性,取特征值的前K个项,可以近似的表示矩阵Data:

那么,近似矩阵相对于原始矩阵丢失的部分是什么 ? 其实丢失这部分是一些无关信息,利用这点可以达到降噪的效果。

用一个图片处理的例子,能很好的说明这一点。

上一张美女图片

 

可以看到脸蛋中心有个小黑斑。接下来,用对这个图片svd分解。然后取某个维度的特征进行还原。

python 代码

# -*- coding:utf-8 -*- 
from numpy import linalg, mat, dot, eye
from PIL import Image
 
def main(num=5):
    im = Image.open('d:\\s1.jpg')
    box = (0, 0, im.size[0], im.size[1])
    imcopy = im.crop(box)
    pix = imcopy.load()
    ma = [[], [], []]
    num= int(im.size[1]*1/6)

    for i in xrange(3):
        for x in xrange(im.size[0]):
            ma[i].append([])
            for y in xrange(im.size[1]):
                ma[i][-1].append(pix[x, y][i])
            
    for i in xrange(3):
        u, s, v = linalg.svd(ma[i])
        s2 =mat(eye(num)*s[:num])  
        ma[i]=u[:, :num]*s2*v[:num, :]

    for x in xrange(im.size[0]):
        for y in xrange(im.size[1]):
            ret = []
            for i in xrange(3):
                tmp = int(ma[i][x,y])
                if tmp < 0:
                    tmp = 0
                if tmp > 255:
                    tmp = 255
                ret.append(tmp)
            pix[x, y] = tuple(ret)
    imcopy.show()

   # imcopy.save('d:\\s2.jpg')
 
if __name__ == '__main__':
    main()

还原后效果,可以发现脸蛋中心有个小黑斑不见了。是不是起到了降噪的效果。

 

 

参考学习的链接

http://www.isnowfy.com/introduction-to-svd-and-lsa/

http://blog.csdn.net/redline2005/article/details/24100293

http://blog.csdn.net/moodytong/article/details/10085215

https://share.coursera.org/wiki/index.php/ML:Dimensionality_Reduction

posted on 2016-01-19 17:08 张日海 阅读(...) 评论(...) 编辑 收藏

导航