1.基本介绍
就个人看来,其实SVD(singular valur decomposition)和PCA的功能是一样的,可以用来降低维度、去除噪声,经过PCA和SVD处理后的数据可以做各种处理,包括之前的各个分类和回归的经典算法等,可以说SVD和PCA是高级别的预处理(相对于均值归一化、属性范围调整等)。
2.SVD简要说明
一般地,获得sigma矩阵中,绝大多数对角元素为0;一般选择部分来简化数据,即sigma的维度变为m*k,U的维度变为m*k。
3.基于协同过滤的推荐
这里我们假设有m个用户,n个物品,原始的数据矩阵Data为m*n维度,矩阵中的元素是用户对物品的评分,如果用户没有对该物品进行评分,则评分为0。协同过滤较为经典的两个是基于物品相似度的和基于用户相似度的,在基于物品相似度计算时,物品的特征维度是用户,数据是评分;在基于用户相似度时,用户的特征维度是物品,数据是评分。可以看到用户和物品互相为特征,但是其中有很多杂质掺杂其中,用SVD可以很好的进行过滤,从而提升推荐结果。
具体做法是(基于物品相似度):对于某个用户u推荐某个物品v时,计算该物品v与u已经评分过的物品相似度,在计算的时候,其特征是通过上面矩阵分解后的V公式重构的,可以看成将物品的特征维度将为了k,物品特征矩阵为n*k,而不是之前的n*m。
4.进一步的改进LFM
在进行SVD运算时,随着物品和项目的增多,计算复杂度会非常高。这时出现了LFM即latent factor model,这里的假设和SVD十分相似,即评分矩阵Data是由两个矩阵乘积所得,一个是用户特征矩阵,其维度为m*k,另外一个是物品特征矩阵,其维度为n*k,那么用户特征矩阵*物品特征矩阵的转置,即得到了评分矩阵。需要对m*k+n*k个参数进行求解,而求解的目标就是让得到的评分和实际评分平方差之和最小。这个具体可以参照《推荐系统实战》,里面有相关的代码和说明。
5.SVD用于推荐的示例
三种不同计算相似度的方法:ecludSim/pearsSim/cosSim;standEst是基于原始数据计算非评分物品和评分物品之间的相似度;而svdEst在计算之前,对数据进行了重构(这里默认重构为n*4的矩阵);主函数recommend中可以指定相似度计算和评分预测方法,还有物品推荐个数N(默认为3)。
from numpy import *
import matplotlib.pyplot as plt
from numpy import linalg as la
def ecludSim(inA, inB):
return 1.0/(1.0+la.norm(inA-inB))
def pearsSim(inA, inB):
if len(inA)<3:return 1.0
return 0.5+0.5*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)
def standEst(dataMat, user, simMeas, item):
n=shape(dataMat)[1]
simTotal=0.0
ratSimTotal=0.0
for j in range(n):
userRating=dataMat[user,j]
if userRating==0:continue
overLap=nonzero(logical_and(dataMat[:,item].A>0,dataMat[:,j].A>0))[0]
if len(overLap)==0:
simliarity=0
else:
similarity=simMeas(dataMat[overLap,item],dataMat[overLap,j])
simTotal+=similarity
ratSimTotal+=similarity*userRating
if simTotal==0:return 0
return ratSimTotal/simTotal
def svdEst(dataMat, user, simMeas, item):
n=shape(dataMat)[1]
simTotal=0.0
ratSimTotal=0.0
U, Sigma, VT=la.svd(dataMat)
Sig4=mat(eye(4)*Sigma[:4])
xformedItems=dataMat.T*U[:,:4]*Sig4.I
for j in range(n):
userRating=dataMat[user,j]
if userRating==0 or j==item:continue
similarity=simMeas(xformedItems[item,:].T,xformedItems[j,:].T)
simTotal+=similarity
ratSimTotal+=similarity*userRating
if simTotal==0:return 0
return ratSimTotal/simTotal
def recommend(dataMat, user, N=3, simMeas=cosSim, estMethod=standEst):
unratedItems=nonzero(dataMat[user,:].A==0)[1]
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=lambda jj:jj[1], reverse=True)[:N]
myData=[[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]]
myMat=mat(myData)
print "standESt"
print recommend(myMat,2)
print "svdEst"
print recommend(myMat,2,3,cosSim,svdEst)