python-构建推荐引擎

# -*- 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;

print(ssT)

推荐系统需要注意主要几个问题:

(1)存储时有大量0,要考虑使用稀疏矩阵。

(2)在计算商品相似度,需要考虑是否能复用,否则,计算量太大了。

(3)冷启动问题,也就是如何在缺乏数据时给出好的推荐呢,实际应用时要充分考虑。

猜你喜欢

转载自blog.csdn.net/weixin_42039090/article/details/80540243