zoukankan      html  css  js  c++  java
  • 利用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)]
  • 相关阅读:
    LeetCode Single Number
    Leetcode Populating Next Right Pointers in Each Node
    LeetCode Permutations
    Leetcode Sum Root to Leaf Numbers
    LeetCode Candy
    LeetCode Sort List
    LeetCode Remove Duplicates from Sorted List II
    LeetCode Remove Duplicates from Sorted List
    spring MVC HandlerInterceptorAdapter
    yum
  • 原文地址:https://www.cnblogs.com/gezhuangzhuang/p/10205284.html
Copyright © 2011-2022 走看看