本篇整理了一些SVD奇异值分解在机器学习中的应用:
- SVD奇异值分解
- SVD在推荐算法中的应用
- PCD 数据降维
- 一个图片处理的例子
SVD奇异值分解
讲svd之前,先了解一下特征向理和特征值的概念。
对于一个方阵M,如果有向量v 和 数值 λ ,Mv = λv,则 v 称为 M 的对应于特征值 λ 的特征向量。
特征分解: 方阵M可以被分解为 M =Q∗Λ∗Q−1 Q∗Λ∗Q−1Q∗Λ∗Q−1
其中Q 是N×N方阵,由特征向量组成的矩阵,且其第 i 列为 M 的第i个特征向量 。 Λ 是对角矩阵,其对角线上的元素为对应的特征值。
SVD奇异值分解和特征分解很像,区别就是此时Data 是一个m * n的矩阵,不是方阵。
矩阵Data可被分解为三个矩阵
Σ
和VT
就分别是m* m、m*n和n*n。Σ
为对角矩阵,对角元素称为奇异值。
SVD 和 特征分解的关系:
Data * DataT
是个方阵,特征分解可得 Data *
Data
T
= U mxm *
Σ
1* U
T
mxm
Data
T
* Data
是个方阵,特征分解可得
= V nxn Data
T
* Data
*
Σ
2* VT
nxn
svd 分解中
U mxm 就是
Data * DataT
的特征向量,V nxn 就是
Data
T
* 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