1 SVD简介
(1)作用:简化数据,去除噪声数据和冗余信息,
(2)主要应用:推荐系统
(3)公式:
(4)SVD思想:将数据按上面的公式分解成三部分,为数据集的特征值;是一个对角矩阵其他元素均为0,那些对角元素称为奇异值,这里有个性质:在某个奇异值之后,其他的奇异值都为0,我们就认为为0的奇异值对应的数据集是不重要的,可以去掉的。
U ,sigma,V=linalg.svd(data)
(5)实现:python中的Numpy库中有个现成的linalg包,可以直接使用。
求得sigma之后,根据sigma矩阵,重构近似原始矩阵。
(6)基于协同过滤的推荐引擎:
通过将用户和其他用户的数据进行对比来实现推荐,对比的标准为相似度的比较。这是基于用户的相似度来实现推荐,实际中,物品的总数往往比用户的总数少,所以,一般采用基于物品相似度来构建推荐引擎。
相似度的计算常见有三种:1)通过计算两商品的欧氏距离 ecludSim(inA,inB)
2)皮尔逊相关系数计算 pearsSim(inA,inB)
3)余弦相似度 cosSim(inA,inB)
2 实例:餐馆菜肴推荐引擎
推荐引擎需要实现的工作流程是:给定一个用户user,通过这个用户之前对其他菜肴的历史评分来预测没有评分的菜肴的评分值,最后根据评分值大小的排序,推荐评分值最大的菜肴。
实现:
#dataMat矩阵的行表示用户,列表示物品,里面的元素,表示某用户对某物品的评分
# 该函数实现两物品相似度的计算,返回当前用户user对没有评分的物品的预测评分值
def standEst(dataMat, user, simMeas, item):
n = shape(dataMat)[1]
simTotal = 0.0; ratSimTotal = 0.0
#遍历user那行的每一列 ,也就是遍历当前用户对所有物品的历史评分
for j in range(n):
userRating = dataMat[user,j]
#跳过该用户没有评分的物品
if userRating == 0: continue
#dataMat[:,n].A>0 表示矩阵dataMat的第N列所有元素大于0的逻辑结果
#overLap返回当前用户历史有评分记录的物品编号
overLap = nonzero(logical_and(dataMat[:,item].A>0,dataMat[:,j].A>0))[0]
if len(overLap) == 0: similarity = 0
#计算物品item与j的相似度,也就是计算当前用户user没有评分的物品与已评分物品的相似度
else: similarity = simMeas(dataMat[overLap,item],dataMat[overLap,j])
print 'the %d and %d similarity is: %f' % (item, j, similarity)
simTotal += similarity #每个已评分物品与未评分物品都有一个相似度,将所有计算的相似度求和
ratSimTotal += similarity * userRating #相似度与当前用户user的评分乘积
if simTotal == 0: return 0
else: return ratSimTotal/simTotal
def recommend(dataMat, user, N=3, simMeas=cosSim, estMethod=standEst):
unratedItems = nonzero(dataMat[user,:].A==0)[1]#找到未评级的物品,也就是在user=n那一行中找到元素为0的列号
if len(unratedItems) == 0: return 'you rated everything'
itemScores = []
#遍历user用户没有进行评分的物品
for item in unratedItems:
#预测当前用户user对当前没有评分的物品item的评分值
estimatedScore = estMethod(dataMat, user, simMeas, item)
#对当前用户user对所有没有评分的unratedItems物品的预测的评分值进行从大到小的排序
itemScores.append((item, estimatedScore))
return sorted(itemScores, key=lambda jj: jj[1], reverse=True)[:N] #N表示显示的推荐菜肴的数量
3 利用SVD提高推荐的效果
因为在实际中,数据集很稀疏,所以需要对数据集“浓缩”处理。
def svdEst(dataMat, user, simMeas, item):
n = shape(dataMat)[1]
simTotal = 0.0; ratSimTotal = 0.0
U,Sigma,VT = la.svd(dataMat) #SVD分解
Sig4 = mat(eye(4)*Sigma[:4]) #arrange Sig4 into a diagonal matrix
xformedItems = dataMat.T * U[:,:4] * Sig4.I #重建去除噪音的数据集
#j为遍历当前用户具有评分历史记录的所有物品
#item为遍历当前用户没有评分历史记录的所有物品
for j in range(n):
userRating = dataMat[user,j]
if userRating == 0 or j==item: continue
similarity = simMeas(xformedItems[item,:].T,xformedItems[j,:].T)
print 'the %d and %d similarity is: %f' % (item, j, similarity)
simTotal += similarity
ratSimTotal += similarity * userRating
if simTotal == 0: return 0
else: return ratSimTotal/simTotal