• 利用SVD-推荐未尝过的菜肴2


    推荐未尝过的菜肴-基于SVD的评分估计

    实际上数据集要比我们上一篇展示的myMat要稀疏的多。

    from numpy import linalg as la
    from numpy import *
    def 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]]

    一、计算一下到底有多少个奇异值能达到总能量的90%(下一篇我们将用一个函数实现该功能)

    U, Sigma, VT = la.svd(mat(loadExData2()))
    Sigma
    array([15.77075346, 11.40670395, 11.03044558,  4.84639758,  3.09292055,
            2.58097379,  1.00413543,  0.72817072,  0.43800353,  0.22082113,
            0.07367823])
    总能量:
    Sig2 = Sigma ** 2 
    sum(Sig2)
    541.9999999999995
    总能量的90%:
    sum(Sig2) * 0.9
    487.7999999999996
    计算前两个元素所包含的能量:
    sum(Sig2[:2])
    378.8295595113579
    该值低于总能量的90%,计算前三个元素所包含的能量:
    sum(Sig2[:3])
    500.5002891275793
    该值高于总能量的90%,我们将一个11维的矩阵转换成一个三维的矩阵,下面对转换后的三维空间构造出一个相似度计算函数

    二、相似度计算(欧式距离、皮尔逊相关系数、余弦相似度)

    # 相似度计算
    # 计算欧式距离
    def ecludSim(inA, inB):
        return 1.0 / (1.0 + la.norm(inA - inB))
    
    # pearsim()函数会检查是否存在3个或更多的点
    # corrcoef直接计算皮尔逊相关系数,范围[-1, 1],归一化后[0, 1]
    def pearsSim(inA, inB):
        # 如果不存在,该函数返回1.0,此时两个向量完全相关
        if len(inA) < 3:
            return 1.0
        return 0.5 + 0.5 * corrcoef(inA, inB, rowvar=0)[0][1]
    
    # 计算余弦相似度,如果夹角为90度,相似度为0;如果两个向量的方向相同,相似度为1.0
    def cosSim(inA, inB): 
        num = float(inA.T * inB)
        denom = la.norm(inA) * la.norm(inB)
        return 0.5 + 0.5 * (num / denom)

    三、基于SVD的评分估计

    # 基于SVD的评分估计
    # 在recommend()中,这个函数用于替换对standEst()的调用,该函数对给定用户、给定物品构建了一个评分估计值
    def svdEst(dataMat, user, simMeas, item):
        """svdEst()
        
        Args:
            dataMat  训练数据集
            user     用户编号
            simMeas  相似度计算方法
            item     未评分的物品编号
        Returns:
            ratSimTotal / simTotal   评分(0~5之间的值)
        """
        # 物品数目
        n = shape(dataMat)[1]
        # 对数据集进行SVD分解
        simTotal = 0.0
        ratSimTotal = 0.0
        
        # 奇异值分解
        # 在SVD分解之后,我们只利用包含了90%能量值的奇异值,这些奇异值会以Numpy数组的形式得以保存
        U, Sigma, VT = la.svd(dataMat)
        
        # 如果要进行矩阵运算,就必须要用这些奇异值构建出一个对角矩阵
        Sig4 = mat(eye(4) * Sigma[: 4])
        
        # 利用U矩阵将物品转换到低维空间中,构建转换后的物品
        xformedItems = dataMat.T * U[:, :4] * Sig4.I
        
        # 对于给定的用户,for循环在用户对应行的元素上进行遍历
        # 这和standEst()函数中的for循环的目的一样,只不过这里的相似度计算是在低维空间下进行的
        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
        else:
            # 计算估计评分
            return ratSimTotal/simTotal

    四、排序获取最后的推荐结果

    # recommend()函数,就是推荐引擎,它默认调用 svdEst()函数,产生了最高的N个推荐结果
    # 如果不指定N的大小,则默认值为3,该函数另外的参数该包括相似度计算方法和估计方法
    def recommend(dataMat, user, N=3, simMeas=cosSim, estMethod=svdEst):
        """recommend()
        Args:
            dataMat 训练数据集
            user    用户编号
            simMeas 相似度计算方法
            estMethod 使用的推荐算法
        Returns:
            返回最终N个推荐结果
        """
        # 寻找未评级的物品
        # 对给定用户建立一个未评分的物品列表
        unratedItems = nonzero(dataMat[user, :].A == 0)[1]
        # 如果不存在未评分物品,那么就退出函数
        if len(unratedItems) == 0:
            return 'you rated everything'
        # 物品的编号和评分值
        itemScores = []
        for item in unratedItems:
            # 获取 item 该物品的评分
            estimatedScore = estMethod(dataMat, user, simMeas, item)
            itemScores.append((item, estimatedScore))
        # 按照评分得分,进行逆排序,获取前N个未评级物品进行推荐
        return sorted(itemScores, key=lambda jj: jj[1], reverse=True)[: N]
    myMat = mat(loadExData2())
    recommend(myMat, 1, simMeas=pearsSim)
    [(4, 3.346952186702173), (9, 3.33537965732747), (6, 3.3071930278130366)]
    这表明用户1(从0开始计数,对应是矩阵第2行),对物品4的预测评分为3.34,对物品9预测评分为3.33,对物品6预测评分为3.30
    试试另一种相似度
    recommend(myMat, 1, simMeas=cosSim)
    [(4, 3.344714938469228), (7, 3.3294020724526967), (9, 3.3281008763900686)]
  • 相关阅读:
    Unix/Linux环境C编程入门教程(23) 字符数字那些事儿
    Unix/Linux环境C编程入门教程(22) C/C++如何获取程序的运行时间
    如何定义函数模板
    Unix/Linux环境C编程入门教程(21) 各个系统HelloWorld跑起来效果如何?
    为什么使用模板
    CC++初学者编程教程(16) 搭建Xcode cocos2dx开发环境
    delete noprompt archivelog 报错ORA-00245,RMAN-08132
    RMAN-03002、RMAN-06059
    RAC RMAN 备份 RMAN-03009 ORA-19504 ORA-27040 RMAN-06012 channel c3 not allocated 错误分析
    RMAN备份到NFS,报错 ORA-27054
  • 原文地址:https://www.cnblogs.com/gezhuangzhuang/p/10205284.html
Copyright © 2020-2023  润新知