# -*- coding: utf-8 -*-
"""
推荐系统的过程:给定一个用户,系统会为此用户返回N个最好的推荐菜。为了实现这个目的:
(1)寻找用户没有评级的菜肴,即在用户-物品矩阵中的0值。
(2)在用户没有评级的所有物品中,对每个物品预计一个可能的评级分数。这就是说,我们认为
用户可能会对物品的打分(这就是相似度计算的初衷)
(3)对这些物品的评分从高到低进行排序,返回前N个物品。
"""
from numpy import *
from numpy import linalg as la
import numpy as np
def loadExData():
return[[0, 0, 0, 2, 2],
[0, 0, 0, 3, 3],
[0, 0, 0, 1, 1],
[1, 1, 1, 0, 0],
[2, 2, 2, 0, 0],
[5, 5, 5, 0, 0],
[1, 1, 1, 0, 0]]
def loadExData2(): #11行11列。
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 ecludSim(inA,inB,axis=0):
return 1.0/(1.0+la.norm(inA-inB)) #inA,inB是列向量
def pearSim(inA,inB,axis=0):
# print(inA,len(inA))
if len(inA)<3:
return 1.0
else:
# print("corrcoef(inA,inB,rowvar=0)",corrcoef(inA,inB,rowvar=0))
#对称矩阵,且corrcoef是x1x1,x1x2,x2x1,x2x2这四者系数。
# print("corrcoef(inA,inB,rowvar=0)[0]",corrcoef(inA,inB,rowvar=0)[0])
#由于两个变量,所以取第一行就是x1对所有变量的线性相关性,协方差。
# print("corrcoef(inA,inB,rowvar=0)[0][1]",corrcoef(inA,inB,rowvar=0)[0][1])
#第一行第二列就是x2x1,第二列和第二行一样都是第二个变量对所有其他变量的线性相关性。
if axis==0:
return 0.5+0.5*corrcoef(inA,inB,rowvar=0)[0][1]
else:
return 0.5+0.5*corrcoef(inA,inB,rowvar=1)[0][1]
#思想一致,但是求值不一样而已
def cosSim(inA,inB,axis=0):#inA,inB是列向量
if axis==0:
num=float(inA.T*inB) #一行乘以一列,才能为数。
else:
num=float(inA*inB.T) #一行乘以一列,才能为数,原理一样。
denom=la.norm(inA)*la.norm(inB)
return 0.5+0.5*(num/denom)
#------------standEst函数---功能:用户对物品的估计评分值。-----
#输入参数四个:数据矩阵、用户编号、物品编号和相似度计算。
#功能:计算用户对物品的估计评分值,评价分数怎么算法出来的呢?
#相似度越高的人,是不是就是根据它推荐的权值就越高呢。
#所有预测,要不和同质间找相似,要不和异质间找差异;所有机器学习算法不都是这个原理吗?
#输出:
def standEst(dataMat,user,simMeas,item):
n=shape(dataMat)[1] #n colunmn_num
# print("n=",n)
simTotal=0.0; #sim total
ratSimTotal=0.0 #
for j in range(n): #从第一个商品开始搜索。
userRating=dataMat[user,j] #获取当前用户对应的第j个商品评价。
# print("userRating",dataMat[user,j])
if userRating==0:
continue #如果获取的值为0,代表没有评价。
overLap=nonzero(logical_and(dataMat[:,item].A>0,dataMat[:,j].A>0))[0]
# print("dataMat[:,item].A>0",dataMat[:,item].A>0)
# print("dataMat[:,{}].A>0".format(j),dataMat[:,j].A>0)
# print("np.logical_and(dataMat[:,item].A>0,dataMat[:,j].A>0)",ss)
# print("overLap",overLap)
#item是待评价的商品,将别人评价已经对该商品有评价过的,将分数的记录下。
#如果不存在,相似度返回为0
# print("overLap",overLap,len(overLap))
if len(overLap)== 0:simliarity=0
else:
simliarity=simMeas(dataMat[overLap,item],dataMat[overLap,j])
#计算:两者之间的相似度方法。
# print("the {0} and {1} similarity is :{2}".format(item,j,simliarity))
simTotal+=simliarity
# print("simTotal",simTotal)
ratSimTotal+=simliarity*userRating#和商品相似度有关。
# print("ratSimTotal",ratSimTotal)
if simTotal==0:
return 0
else:
return ratSimTotal/simTotal
#--------------------------------利用SVD降维技术----------------------------
def svdEst(dataMat, user, simMeas, item):
n = shape(dataMat)[1] #商品数量。
simTotal = 0.0; ratSimTotal = 0.0
U,Sigma,VT = la.svd(dataMat) #先SVD分解。
# print("Sigma=",Sigma,"shape(U)",shape(U))
Sig4 = mat(eye(4)*Sigma[:4]) #arrange Sig4 into a diagonal matrix
# print("eye(4)*Sigma[:4]",eye(4)*Sigma[:4]) #形成对角矩阵。4行4列。
# print("sig4.I=",Sig4.I,Sig4.I[0][0]*Sig4[0][0])
xformedItems = dataMat.T * U[:,:4] * Sig4.I #create transformed items
#dataMat 11*11;U 11*11 U[:,:4] 11行4列 Sig4.I 4*4 result:11*4
#行表示的商品相似度了。
# print("xformedItems",xformedItems,"shape(xformedItems)",shape(xformedItems))
for j in range(n):
userRating = dataMat[user,j]
if userRating == 0 or j==item: continue
similarity = simMeas(xformedItems[item,:],xformedItems[j,:],axis=1)
#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
#--------------------------------------------推荐系统-------------------------
def recommend(dataMat,user,N=3,simMeas=cosSim,estMethod=standEst):
unratedItems=nonzero(dataMat[user,:].A==0)[1]
# print("unratedItems",unratedItems)
#dataMat[user,:].A==0 表示第user用户所有的商品评价中等于0,为True,值为1;
#为FALSE,值为0;
#nonzero不是非零的行列号,只需要列号,因为列号是对应的商品序列号的(未推荐)矩阵。
if len(unratedItems)==0: #如果该用户不存在,就直接返回了。
return "you rated everything"
itemScores=[] #项目分数,用列表存放。
for item in unratedItems: #搜索未推荐的项目,逐个遍历。
estimatedScore=estMethod(dataMat,user,simMeas,item)
#由于estMethod=standEst。
#实际上是:standEst(dataMat,user,simMeas,item)。
itemScores.append((item,estimatedScore))
#求出item序号,即对应的推荐分数。(item,estimatedScore)很关键。
# print("itemScores=",itemScores)
return sorted(itemScores,key=lambda jj:jj[1],reverse=True)[:N]
#根据推荐的分数关键字进行排序,这种写法高效简洁返回。
data=mat(loadExData2())
#m,n=shape(data)
#U,Sigma,VT=la.svd(data)
#tt=sum(Sigma**2)
#print([sum(Sigma[:y]**2)*100/tt for y in range( 11)] )
##求商品(列)相似度。
#print("ecludSim=",ecludSim(data[:,0],data[:,4],0))
#print("pearSim=",pearSim(data[:,0],data[:,4],0))
#print("cosSim=",cosSim(data[:,0],data[:,4],0))
##求顾客、用户(行)相似度。
##-------------------------------------------------
#print("ecludSim=",ecludSim(data[0,:],data[1,:],1))
#print("pearSim=",pearSim(data[1,:],data[2,:],1))
#print("cosSim=",cosSim(data[0,:],data[1,:],1))
#------------------------------------------------------------------
#print("data=",shape(data))
ssT=recommend(data,1,simMeas=cosSim,estMethod=svdEst)#user为2.
#返回一个列表,包括2个元组,第一个元组是第5个商品,预测评分为2.0;
print(ssT)
ssT=recommend(data,1,simMeas=cosSim,estMethod=standEst)#user为2.
#返回一个列表,包括2个元组,第一个元组是第5个商品,预测评分为2.0;
"""
推荐系统的过程:给定一个用户,系统会为此用户返回N个最好的推荐菜。为了实现这个目的:
(1)寻找用户没有评级的菜肴,即在用户-物品矩阵中的0值。
(2)在用户没有评级的所有物品中,对每个物品预计一个可能的评级分数。这就是说,我们认为
用户可能会对物品的打分(这就是相似度计算的初衷)
(3)对这些物品的评分从高到低进行排序,返回前N个物品。
"""
from numpy import *
from numpy import linalg as la
import numpy as np
def loadExData():
return[[0, 0, 0, 2, 2],
[0, 0, 0, 3, 3],
[0, 0, 0, 1, 1],
[1, 1, 1, 0, 0],
[2, 2, 2, 0, 0],
[5, 5, 5, 0, 0],
[1, 1, 1, 0, 0]]
def loadExData2(): #11行11列。
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 ecludSim(inA,inB,axis=0):
return 1.0/(1.0+la.norm(inA-inB)) #inA,inB是列向量
def pearSim(inA,inB,axis=0):
# print(inA,len(inA))
if len(inA)<3:
return 1.0
else:
# print("corrcoef(inA,inB,rowvar=0)",corrcoef(inA,inB,rowvar=0))
#对称矩阵,且corrcoef是x1x1,x1x2,x2x1,x2x2这四者系数。
# print("corrcoef(inA,inB,rowvar=0)[0]",corrcoef(inA,inB,rowvar=0)[0])
#由于两个变量,所以取第一行就是x1对所有变量的线性相关性,协方差。
# print("corrcoef(inA,inB,rowvar=0)[0][1]",corrcoef(inA,inB,rowvar=0)[0][1])
#第一行第二列就是x2x1,第二列和第二行一样都是第二个变量对所有其他变量的线性相关性。
if axis==0:
return 0.5+0.5*corrcoef(inA,inB,rowvar=0)[0][1]
else:
return 0.5+0.5*corrcoef(inA,inB,rowvar=1)[0][1]
#思想一致,但是求值不一样而已
def cosSim(inA,inB,axis=0):#inA,inB是列向量
if axis==0:
num=float(inA.T*inB) #一行乘以一列,才能为数。
else:
num=float(inA*inB.T) #一行乘以一列,才能为数,原理一样。
denom=la.norm(inA)*la.norm(inB)
return 0.5+0.5*(num/denom)
#------------standEst函数---功能:用户对物品的估计评分值。-----
#输入参数四个:数据矩阵、用户编号、物品编号和相似度计算。
#功能:计算用户对物品的估计评分值,评价分数怎么算法出来的呢?
#相似度越高的人,是不是就是根据它推荐的权值就越高呢。
#所有预测,要不和同质间找相似,要不和异质间找差异;所有机器学习算法不都是这个原理吗?
#输出:
def standEst(dataMat,user,simMeas,item):
n=shape(dataMat)[1] #n colunmn_num
# print("n=",n)
simTotal=0.0; #sim total
ratSimTotal=0.0 #
for j in range(n): #从第一个商品开始搜索。
userRating=dataMat[user,j] #获取当前用户对应的第j个商品评价。
# print("userRating",dataMat[user,j])
if userRating==0:
continue #如果获取的值为0,代表没有评价。
overLap=nonzero(logical_and(dataMat[:,item].A>0,dataMat[:,j].A>0))[0]
# print("dataMat[:,item].A>0",dataMat[:,item].A>0)
# print("dataMat[:,{}].A>0".format(j),dataMat[:,j].A>0)
# print("np.logical_and(dataMat[:,item].A>0,dataMat[:,j].A>0)",ss)
# print("overLap",overLap)
#item是待评价的商品,将别人评价已经对该商品有评价过的,将分数的记录下。
#如果不存在,相似度返回为0
# print("overLap",overLap,len(overLap))
if len(overLap)== 0:simliarity=0
else:
simliarity=simMeas(dataMat[overLap,item],dataMat[overLap,j])
#计算:两者之间的相似度方法。
# print("the {0} and {1} similarity is :{2}".format(item,j,simliarity))
simTotal+=simliarity
# print("simTotal",simTotal)
ratSimTotal+=simliarity*userRating#和商品相似度有关。
# print("ratSimTotal",ratSimTotal)
if simTotal==0:
return 0
else:
return ratSimTotal/simTotal
#--------------------------------利用SVD降维技术----------------------------
def svdEst(dataMat, user, simMeas, item):
n = shape(dataMat)[1] #商品数量。
simTotal = 0.0; ratSimTotal = 0.0
U,Sigma,VT = la.svd(dataMat) #先SVD分解。
# print("Sigma=",Sigma,"shape(U)",shape(U))
Sig4 = mat(eye(4)*Sigma[:4]) #arrange Sig4 into a diagonal matrix
# print("eye(4)*Sigma[:4]",eye(4)*Sigma[:4]) #形成对角矩阵。4行4列。
# print("sig4.I=",Sig4.I,Sig4.I[0][0]*Sig4[0][0])
xformedItems = dataMat.T * U[:,:4] * Sig4.I #create transformed items
#dataMat 11*11;U 11*11 U[:,:4] 11行4列 Sig4.I 4*4 result:11*4
#行表示的商品相似度了。
# print("xformedItems",xformedItems,"shape(xformedItems)",shape(xformedItems))
for j in range(n):
userRating = dataMat[user,j]
if userRating == 0 or j==item: continue
similarity = simMeas(xformedItems[item,:],xformedItems[j,:],axis=1)
#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
#--------------------------------------------推荐系统-------------------------
def recommend(dataMat,user,N=3,simMeas=cosSim,estMethod=standEst):
unratedItems=nonzero(dataMat[user,:].A==0)[1]
# print("unratedItems",unratedItems)
#dataMat[user,:].A==0 表示第user用户所有的商品评价中等于0,为True,值为1;
#为FALSE,值为0;
#nonzero不是非零的行列号,只需要列号,因为列号是对应的商品序列号的(未推荐)矩阵。
if len(unratedItems)==0: #如果该用户不存在,就直接返回了。
return "you rated everything"
itemScores=[] #项目分数,用列表存放。
for item in unratedItems: #搜索未推荐的项目,逐个遍历。
estimatedScore=estMethod(dataMat,user,simMeas,item)
#由于estMethod=standEst。
#实际上是:standEst(dataMat,user,simMeas,item)。
itemScores.append((item,estimatedScore))
#求出item序号,即对应的推荐分数。(item,estimatedScore)很关键。
# print("itemScores=",itemScores)
return sorted(itemScores,key=lambda jj:jj[1],reverse=True)[:N]
#根据推荐的分数关键字进行排序,这种写法高效简洁返回。
data=mat(loadExData2())
#m,n=shape(data)
#U,Sigma,VT=la.svd(data)
#tt=sum(Sigma**2)
#print([sum(Sigma[:y]**2)*100/tt for y in range( 11)] )
##求商品(列)相似度。
#print("ecludSim=",ecludSim(data[:,0],data[:,4],0))
#print("pearSim=",pearSim(data[:,0],data[:,4],0))
#print("cosSim=",cosSim(data[:,0],data[:,4],0))
##求顾客、用户(行)相似度。
##-------------------------------------------------
#print("ecludSim=",ecludSim(data[0,:],data[1,:],1))
#print("pearSim=",pearSim(data[1,:],data[2,:],1))
#print("cosSim=",cosSim(data[0,:],data[1,:],1))
#------------------------------------------------------------------
#print("data=",shape(data))
ssT=recommend(data,1,simMeas=cosSim,estMethod=svdEst)#user为2.
#返回一个列表,包括2个元组,第一个元组是第5个商品,预测评分为2.0;
print(ssT)
ssT=recommend(data,1,simMeas=cosSim,estMethod=standEst)#user为2.
#返回一个列表,包括2个元组,第一个元组是第5个商品,预测评分为2.0;
print(ssT)
推荐系统需要注意主要几个问题:
(1)存储时有大量0,要考虑使用稀疏矩阵。
(2)在计算商品相似度,需要考虑是否能复用,否则,计算量太大了。
(3)冷启动问题,也就是如何在缺乏数据时给出好的推荐呢,实际应用时要充分考虑。