机器学习-python利用SVD编写推荐引擎

来源:互联网 发布:医疗器械软件 编辑:程序博客网 时间:2024/06/03 20:12

代码及数据集下载:SVD
SVD(Singular Value Decomposition)主要用来进行数据降维、特征提取、消除数据噪声、消去数据中的冗余信息、数据压缩等。用于提高机器学习算法的效果,或压缩数据存储空间。利用SVD能够用小的多的数据集表示原始数据,其实质是去除了噪声以及冗余项。SVD常用于隐形语义检索的搜索系统(LSI)、隐性语义分析(LSA)、推荐引擎、图像压缩。这里主要通过推荐引擎的编写,讲述SVD的作用。

—推荐引擎
推荐系统是通过计算项与项之间的相似度而实现。利用SVD可以构建出一个主题空间,在该空间下计算器相似度将更加准确。
SVD的理论在博文机器学习中特征值分解与奇异值分解的区别及应用中查看。
假定数据行为不同的人,列为菜品,元素为对应人对该菜品的打分,0表示没打分。
这里写图片描述
numpy的库函数U,sigma,VT=numpy.linalg.svd()可以方便的实现奇异值分解。
sigma中奇异值的数量选取方法有以下几种:

  • 保留90%的能量信息。

  • 用户自定义

协同过滤:协同过滤是通过将用户和其他用户或物品与其他物品的数据进行对比来实现推荐的。若两个物品的相似度非常高,则可以将其推荐给用户。

相似度计算:

  • 欧氏距离
    A = [a1,a2,a3],B=[b1,b2,b3]
    相似度=11+norm(AB)

  • 皮尔逊相关系数
    可以直接通过numpy.corrcoef()函数计算得到。其直接得到的值在[1,1],通过0.5+0.5*numpy.corrcoef()将其化为[0,1]

  • 余弦相似度
    计算两个向量的余弦值,如果夹角为90°则相似度为0,若同方向,则相似度为1。
    cosθ=AB||A||||B||,也可归一化0.5+0.5cosθ得到。
    代码如下:

def eulidSim(inA,inB):    return 1.0/(1.0+np.linalg.norm(inA-inB))def pearsSim(inA,inB):    if len(inA) < 3:        return 1    return 0.5 + 0.5 * np.corrcoef(inA,inB,rowvar = 0)[0][1]def cosSim(inA,inB):    num = float(inA.T*inB)    demon = np.linalg.norm(inA)*np.linalg.norm(inB)    return 0.5 + 0.5 * (num/demon)

选择基于用户相似度还是基于物品相似度:
基于物品:计算两个物品之间的相似度,来确定推荐物品。计算量随着物品的增加而增加。
基于用户:计算用户的相似度,确定推荐物品。计算量随着用户增加而增加。
对于推荐系统,用户数量远大于物品数量,因此一般选择基于物品的推荐算法。

评价指标:
推荐引擎的评价指标采用最小均方根误差(RMSE),对均方误差的平均值取其平方根。如果评级在1~5星之间,若RMSE=1,则可认为预测值与实际值相差1个等级。

基于SVD的推荐引擎。其思路为

寻找没评价过得菜品计算菜品的预测分数推荐前N个

预测分数的思路为

SVD分解SVD分解后矩阵= data.T * U[:,:N] * sigma(N)for 每个菜品    如果没被用户评价过        continue    如果评价过        使用SVD分解后的矩阵计算相似度        评分累加 = 相似度*评分评分 = 评分累加/相似度累加

完整代码为:

import numpy as npdef 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 eulidSim(inA,inB):#欧式相似度    return 1.0/(1.0+np.linalg.norm(inA-inB))def pearsSim(inA,inB):#皮尔逊相关系数    if len(inA) < 3:        return 1    return 0.5 + 0.5 * np.corrcoef(inA,inB,rowvar = 0)[0][1]def cosSim(inA,inB):#余弦相似度    num = float(inA.T*inB)    demon = np.linalg.norm(inA)*np.linalg.norm(inB)    return 0.5 + 0.5 * (num/demon)def svdEst(dataSet,user,simMeans,item):#基于SVD的评价预测    n = np.shape(dataSet)[1]    U,sigma,VT = np.linalg.svd(dataSet)    sig4 = np.mat(np.eye(4)*sigma[:4])    xformedItems = dataSet.T * U[:,:4] * sig4#    xformedItems = VT[:4,:].T    simTotal = 0    ratSimTotal = 0    for i in range(n):        userRating = dataSet[user,i]        if userRating == 0 or i == item:            continue        similarity = simMeans(xformedItems[i,:].T,xformedItems[item,:].T)        simTotal += similarity        ratSimTotal += similarity * userRating    if simTotal == 0:        return 0    else:        return ratSimTotal/simTotaldef recommend(dataSet,user,N=11,simMeans = cosSim,estMethod = svdEst):#推荐引擎    unratedItems = np.nonzero(dataSet[user,:]==0)[1]    if len(unratedItems) == 0:        return 'every dish have been rate'    itemScores = []     for item in unratedItems:        estimatedScore = estMethod(dataSet,user,simMeans,item)        itemScores.append((item,estimatedScore))    return sorted(itemScores,key = lambda pp: pp[1],reverse = True)[:N]data = np.mat(loadExData2())u,sigma,vt = np.linalg.svd(data)sig4 = np.mat(np.eye(4)*sigma[:4])xform = data.T*u[:,:4]*sig4xform2 = sig4 * vt[:4,:]    estimatedScore = recommend(data,6)