奇异值分解SVD实现与应用

SVD是一种提取信息的强大工具,通过SVD实现我们能够用小的多的数据集来表示原始数据集,这样做实际就是去除噪声和冗余信息。

隐性语义索引

SVD最早应用就是信息检索,我们称利用SVD方法为隐性语义索引(LSI),在LSI中一个矩阵是由文档和词语组成,当应用SVD到矩阵上时,就会构建多个奇异值。这些奇异值代表了文档中概念或主题,这一特点可以更高效的文档搜索。

推荐系统

SVD的另外一个应用就是推荐系统,简单版本实现推荐系统就是计算item或者user之间相似性。更先进的方法就是利用SVD从数据中构建一个主题空间,然后在该空间下计算相似度。

基于python对SVD方法在简单推荐系统中实现。

中间用到了python两个很常用函数方法

sorted 方法和 nonzero 方法。

sorted方法是python内置的方法,我们实现中要用到对元组进行排序,如下:

>>> student_tuples = [('john', 'A', 15),('jane', 'B', 12),('dave', 'B', 10),]>>> sorted(student_tuples, key=lambda student: student[2]) # sort by age[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]参考链接:sorted方法

nonzero返回二维的不为0的index,看例子:

>>> a = np.array([[1,2,3],[4,5,6],[7,8,9]])>>> a > 3array([[False, False, False],[ True, True, True],[ True, True, True]], dtype=bool)>>> np.nonzero(a > 3)(array([1, 1, 1, 2, 2, 2]), array([0, 1, 2, 0, 1, 2]))参考链接:nonzero方法

# encoding=utf8import numpy as npfrom numpy import *from numpy import linalg as lafrom operator import itemgetterdef loadExData():return [[4,4,0,2,2],[4,0,0,3,3],[4,0,0,1,1],[1,1,1,2,0],[2,2,2,0,0],[1,1,1,0,0],[5,5,5,0,0]]def loadExData2():return[[0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 5],[0, 0, 0, 3, 0, 4, 0, 0, 0, 0, 3],[0, 0, 0, 0, 4, 0, 0, 1, 0, 4, 0],[3, 3, 4, 0, 0, 0, 0, 2, 2, 0, 0],[5, 4, 5, 0, 0, 0, 0, 5, 5, 0, 0],[0, 0, 0, 0, 5, 0, 1, 0, 0, 5, 0],[4, 3, 4, 0, 0, 0, 0, 5, 5, 0, 1],[0, 0, 0, 4, 0, 4, 0, 0, 0, 0, 4],[0, 0, 0, 2, 0, 2, 5, 0, 0, 1, 2],[0, 0, 0, 0, 5, 0, 0, 0, 0, 4, 0],[1, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0]] def ReconstructSigma(Sigma):return np.mat([[Sigma[0],0,0],[0,Sigma[1],0],[0,0,Sigma[2]]])def ReconstructData(U,Sigma,VT):return U[:,:3]*Sigma*VT[:3,:]# 计算相似性函数def eulidSim(inA,inB):return 1.0/(1.0 + la.norm(inA – inB))#默认计算列做为一个元素之间的距离def pearsSim(inA,inB):if(len(inA)<3): return 1.0return 0.5 + 0.5*np.corrcoef(inA, inB, rowvar=0)[0][1]# 这里返回是一个矩阵,只拿第一行第二个元素def cosSim(inA,inB):num = float(inA.T * inB)denom = la.norm(inA) * la.norm(inB)return 0.5 + 0.5 * (num/denom)'''standEst 需要做的就是估计user 的item 评分,采用方法是 根据物品相似性,及每一列相似性要估计item那一列与其他列进行相似性估计,获得两列都不为0的元素计算相似性然后用相似性乘以 评分来估计未评分的数值 。'''def standEst(dataMat,user,simMeas,item):n = np.shape(dataMat)[1]simTotal = 0.0 ; ratSimTotal = 0.0for j in range(n):userRating = dataMat[user,j]if(userRating == 0): continueoverLap = nonzero(logical_and(dataMat[:,item].A > 0,dataMat[:,j].A >0))[0]# 返回元素不为0的下标'''nonzero 返回参考下面例子,返回二维数组,,第一维是列方向,第二位是行方向'''if(len(overLap)) == 0 :similarity = 0else:similarity = simMeas(dataMat[overLap,item],dataMat[overLap,j])print 'the %d and %d similarity is : %f' %(item,j,similarity)simTotal += similarityratSimTotal += similarity * userRatingif simTotal == 0: return 0else : return ratSimTotal/simTotaldef recommend(dataMat,user ,N = 3,simMeas= cosSim,estMethod = standEst):unratedItems = nonzero(dataMat[user,:].A == 0)[1]# .A 使得矩阵类型转为array'''>>> a = np.array([[1,2,3],[4,5,6],[7,8,9]])>>> a > 3array([[False, False, False],[ True, True, True],[ True, True, True]], dtype=bool)>>> np.nonzero(a > 3)(array([1, 1, 1, 2, 2, 2]), array([0, 1, 2, 0, 1, 2]))'''if len(unratedItems) == 0: return 'you rated everything'itemScores = []for item in unratedItems:estimatedScore = estMethod(dataMat,user,simMeas,item)itemScores.append((item,estimatedScore))return sorted(itemScores,key=itemgetter(1),reverse = True)[:N]def svdEst(dataMat , user, simMeas,item):n = shape(dataMat)[1]simTotal = 0.0 ; ratSimTotal = 0.0U,Sigma,VT = la.svd(dataMat)Sig4 = mat(eye(4) * Sigma[:4]) # 保留最大三个奇异值xformedItems = dataMat.T * U[:,:4] * Sig4.Iprint xformedItemsfor j in range(n):userRating = dataMat[user,j]if userRating == 0 or j==item: continuesimilarity = simMeas(xformedItems[item,:].T,\xformedItems[j,:].T)print 'the %d and %d similarity is: %f' % (item, j, similarity)simTotal += similarityratSimTotal += similarity * userRatingif simTotal == 0: return 0else: return ratSimTotal/simTotalif __name__=="__main__":'''# 测试中间数据Data = loadExData()MatData = np.mat(Data)U,Sigma,VT = np.linalg.svd(Data)print SigmaSigma = ReconstructSigma(Sigma)print Sigmaprint ReconstructData(U, Sigma, VT)print eulidSim(MatData[:,0], MatData[:,4])print cosSim(MatData[:,0], MatData[:,4])print pearsSim(MatData[:,0], MatData[:,0])'''Data = loadExData()dataMat = np.mat(Data)dataMat2 = mat(loadExData2())print dataMat2print recommend(dataMat2, 1,estMethod=svdEst)实现细节参考机器学习实战。

看着你手中的戒指,你说,你可以把它取下来吗?

奇异值分解SVD实现与应用

相关文章:

你感兴趣的文章:

标签云: