赞
踩
SVD降维算法(Singular Value Decompositionm,SVD),即在矩阵论中常见的奇异值分解降维。通俗地讲,就是将一个线性变换分解为两个线性变换,一个线性变换代表旋转,一个线性变换代表拉伸。奇异值分解是在机器学习领域应用较为广泛的算法之一,也是学习机器学习算法绕不开的基石,可应用在特征分解、推荐系统、自然语言处理和计算机视觉等各个方面
SVD降维算法的理论推导让小编觉得很尴尬——学过《矩阵论》这门课的读者,可以直接把这一块儿的内容跳过,进入下一章节;没有学过《矩阵论》的读者,小编也很难像老师在课堂上那样把每一步的原理细细推导讲清楚。此处,还是再一次点亮标题——只作“简洁的理论推导”。
SVD的核心思想是将一个大矩阵转化为几个小矩阵的乘积,如下图所示。
其中,U、S和V分别为分解后的小矩阵,通常更关注S矩阵,S矩阵的每一个值都代表该位置的重要性指标,它与降维算法中的特征值和特征向量的关系类似。
其中n和m都是比较大的数值,代表原始数据;r是较小的数值,表示矩阵分解后的结果用较小的矩阵组合来近似代替。对于奇异值,与特征分解中的特征值类似,在奇异值矩阵中是按照从大到小排序,且奇异值减小得非常快,在大多数情况下,前10%甚至1%的奇异值的和就占了全部的奇异值之和的99%以上的比例。
由于r比n和m小很多,因此原本三个大矩阵(n×n)(n×m)(m×m)可以近似由三个较小的矩阵(n×r)(r×r)(r×m)表示,且原矩阵会在较大程度上保留信息。
由于这个重要的性质,SVD可以用于降维,来做数据压缩和去噪;也可以用于推荐算法,将用户和喜好对应的矩阵做特征分解,进而得到隐含的用户需求来做推荐。同时也可以用于NLP中的算法,比如潜在语义索引(LSI)。
优点:
1.原理和实现步骤都很简单;
2.可实现并行化。
缺点:
1.分解出的矩阵解释性不强,有“黑匣子”的味道;
2.每个基含有不同的鉴别信息和重构信息,且受原始数据的干扰较大。
第一个实战项目,还是以降维开题——创建一个较小的矩阵,模拟用户对商品的评分降维。
import numpy as np class CSVD(object): ''' 实现svd分解降维应用示例的Python代码 ''' def __init__(self, data): self.data = data #用户数据 self.S = [] #用户数据矩阵的奇异值序列 singular values self.U = [] #svd后的单位正交向量 self.VT = [] #svd后的单位正交向量 self.k = 0 #满足self.p的最小k值(k表示奇异值的个数) self.SD = [] #对角矩阵,对角线上元素是奇异值 singular values diagonal matrix def _svd(self): ''' 用户数据矩阵的svd奇异值分解 ''' self.U, self.S, self.VT = np.linalg.svd(self.data) return self.U, self.S, self.VT def _calc_k(self, percentge): '''确定k值:前k个奇异值的平方和占比 >=percentage, 求满足此条件的最小k值 :param percentage, 奇异值平方和的占比的阈值 :return 满足阈值percentage的最小k值 ''' self.k = 0 #用户数据矩阵的奇异值序列的平方和 total = sum(np.square(self.S)) svss = 0 #奇异值平方和 singular values square sum for i in range(np.shape(self.S)[0]): svss += np.square(self.S[i]) if (svss/total) >= percentge: self.k = i+1 break return self.k def _buildSD(self, k): '''构建由奇异值组成的对角矩阵 :param k,根据奇异值开放和的占比阈值计算出来的k值 :return 由k个前奇异值组成的对角矩阵 ''' #方法1:用数组乘方法 self.SD = np.eye(self.k) * self.S[:self.k] #方法2:用自定义方法 e = np.eye(self.k) for i in range(self.k): e[i,i] = self.S[i] return self.SD def DimReduce(self, percentage): ''' SVD降维 :param percentage, 奇异值开方和的占比阈值 :return 降维后的用户数据矩阵 ''' #Step1:svd奇异值分解 self._svd() #Step2:计算k值 self._calc_k(percentage) print('\n按照奇异值开方和占比阈值percentage=%d, 求得降维的k=%d'%(percentage, self.k)) #Step3:构建由奇异值组成的对角矩阵singular values diagonal self._buildSD(self.k) k,U,SD,VT = self.k,self.U, self.SD, self.VT #Step4:按照svd分解公式对用户数据矩阵进行降维,得到降维压缩后的数据矩阵 a = U[:len(U), :k] b = np.dot(SD, VT[:k, :len(VT)]) newData = np.dot(a,b) return newData def CSVD_manual(): ##训练数据集,用户对商品的评分矩阵,行为多个用户对单个商品的评分,列为用户对每个商品的评分 data = np.array([[5, 5, 0, 5], [5, 0, 3, 4], [3, 4, 0, 3], [0, 0, 5, 3], [5, 4, 4, 5], [5, 4, 5, 5]]) percentage = 0.9 svdor = CSVD(data) ret = svdor.DimReduce(percentage) print('====================================================') print('原始用户数据矩阵:\n', data) print('降维后的数据矩阵:\n', ret) print('====================================================') if __name__=='__main__': CSVD_manual()
运行程序,输出如下:
近几年,随着各种短视频和音乐软件日渐火爆,以及各大厂之间的竞争日渐激烈。如何在短时间内让消费者对产品更加感兴趣,如何精准地分析用户心理和用户喜好度,一直是各个大厂孜孜不倦讨论和研究的热门话题。因此,在大厂算法工程师岗位中,日渐独立出一个新的岗位——推荐算法工程师。
借此机会,在这个降维的专题系列里,拓展降维算法的应用实例——应用SVD算法进行音乐推荐(选自《跟着迪哥学python》)。在程序中,首先构建评分矩阵,对其进行SVD分解,再选择待推荐用户,还原得到其对所有歌曲的估测评分值,最后排序,返回结果即可。
由于数据集比较大,且源代码较长,楼主双手奉上源程序和数据集的网盘,关注公众号“码点联盟”(文末有二维码),在后台回复“音乐推荐”即可自动获取网盘资源。
在SVD中所需的数据是用户对商品的打分,但在现在的数据集中,只有用户播放歌曲的情况,并没有实际的打分值,所以,在数据准备阶段,需要定义用户对每首歌曲的评分值。如果一个用户喜欢某首歌曲,他应该经常播放这首歌曲;相反,如果不喜欢某首歌曲,播放次数肯定比较少。
SVD的主体程序如下:
def compute_svd(urm, K): U, s, Vt = svds(urm, K) dim = (len(s), len(s)) S = np.zeros(dim, dtype=np.float32) for i in range(0, len(s)): S[i,i] = mt.sqrt(s[i]) U = csc_matrix(U, dtype=np.float32) S = csc_matrix(S, dtype=np.float32) Vt = csc_matrix(Vt, dtype=np.float32) return U, S, Vt def compute_estimated_matrix(urm, U, S, Vt, uTest, K, test): rightTerm = S*Vt max_recommendation = 250 estimatedRatings = np.zeros(shape=(MAX_UID, MAX_PID), dtype=np.float16) recomendRatings = np.zeros(shape=(MAX_UID,max_recommendation ), dtype=np.float16) for userTest in uTest: prod = U[userTest, :]*rightTerm estimatedRatings[userTest, :] = prod.todense() recomendRatings[userTest, :] = (-estimatedRatings[userTest, :]).argsort()[:max_recommendation] return recomendRatings
最终得到的结果如下:
下一篇,额,小编还没想好,不过,还是以降维为专题。
敬请期待!
欢迎关注公众号“码点联盟”,不定期分享机器学习、深度学习干货,及各种资料大礼包!
另外,这是一个由一线互联网大厂算法工程师及双985研究生创建的公众号,后续会经常分享各类实用机器学习算法技术文章,欢迎交流讨论!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。