美文网首页
机器学习:协同过滤

机器学习:协同过滤

作者: moon_light_ | 来源:发表于2020-03-14 20:58 被阅读0次

    基于协同过滤(collaborative filtering)的推荐引擎,是通过将用户和其他用户的数据进行对比来实现推荐
      
    不是利用属性来描述物品从而计算它们之间的相似度,而是利用用户对它们的意见来计算相似度,这就是协同过滤中所使用的方法,它并不关心物品的描述属性,而是严格地按照许多用户的观点来计算相似度
      
    相似度计算
      欧氏距离
        \small 距离 = \sqrt{(a1-b1)^{2} + (a2-b2)^{2} + ... + (an-bn)^{2}}
        \small 相似度 = \frac{1}{1+距离}
        相似度的范围是 0~1
      
      皮尔逊相关系数 (Pearson correlation)
        该方法相对于欧氏距离的一个优势在于,它对用户评级的量级并不敏感
        比如某个狂躁者对所有物品的评分都是5分
        而另一个忧郁者对所有物品的评分都是1分
        皮尔逊相关系数会认为这两个向量是相等的
        
        在 NumPy 中,皮尔逊相关系数的计算是由函数 corrcoef() 进行的
        通过 0.5 + 0.5*corrcoef() 计算,把取值范围归一化到 0~1
        
      余弦相似度 (cosine similarity)
        计算的是两个向量夹角的余弦值
        如果夹角为 90 度,则相似度为 0,如果两个向量的方向相同,则相似度为 1
        
        \small 相似度 = \frac{A \times B}{||A|| \times ||B||}
        
        \small ||A|| = \sqrt{x_{1}^{2} + x_{2}^{2} + ... + x_{n}^{2}} = np.linalg.norm(A)
      
    计算两个餐馆菜肴之间的距离,这称为基于物品的相似度
    另一种计算用户距离的方法则称为基于用户的相似度
    到底使用哪一种相似度取决于用户或物品的数目
    基于物品相似度计算的时间会随物品数量的增加而增加
    基于用户的相似度计算的时间则会随用户数量的增加而增加
      
    协同过滤是基于用户的相似度计算
      
    代码(使用 SVD 和没使用 SVD 两种)

    # coding=utf-8
    import numpy as np
    
    
    def ecludSim(inA, inB):
        """
        欧氏距离
        """
        return 1.0 / (1.0 + np.linalg.norm(inA - inB))
    
    
    def pearsSim(inA, inB):
        """
        皮尔逊相关系数
        """
        if len(inA) < 3:
            return 1.0
    
        # corrcoef 返回的是矩阵,[0][1] 代表 inA 和 inB 间的相关系数
        return 0.5 + 0.5 * np.corrcoef(inA, inB, rowvar=False)[0][1]
    
    
    def cosSim(inA, inB):
        """
        余弦相似度
        """
        num = float(inA.T * inB)
        denom = np.linalg.norm(inA) * np.linalg.norm(inB)
        return 0.5 + 0.5 * (num / denom)
    
    
    def standEst(dataMat, user, simMeas, item):
        """
        预测 user 对 item 的评分 (没有使用 SVD)
    
        dataMat - 每行是一个用户,每列是该用户对某物品的评分
        user - 要预测的用户
        item - 要预测的物品
        simMeas - 用于计算相似度的函数,ecludSim、pearsSim、cosSim 中的一个
        """
        n = np.shape(dataMat)[1]
    
        simTotal = 0.0
        ratSimTotal = 0.0
    
        # 遍历所有物品
        for j in range(n):
            # 取 user 对 j 的评分
            userRating = dataMat[user, j]
    
            # 没评分则跳过
            if userRating == 0:
                continue
    
            # 找出所有既对 item 有评分,又对 j 有评分的用户
            overLap = np.nonzero(np.logical_and(dataMat[:, item].A > 0, dataMat[:, j].A > 0))[0]
            if len(overLap) == 0:
                similarity = 0
            else:
                # 计算找出来的用户对 item 评分和对 j 评分的相似度
                similarity = simMeas(dataMat[overLap, item], dataMat[overLap, j])
    
            # 累加相似度
            simTotal += similarity
    
            # 累加 user 对 j 的评分与相似度的乘积
            ratSimTotal += similarity * userRating
    
        if simTotal == 0:
            return 0
        else:
            # 预测 user 对 item 的评分,计算方法类似 (a1*x1+a2*x2+...+an*xn)/(x1+x2+...+xn) 其中 xi 是 i 和 item 的相似度,ai 是 user 对 i 的评分
            return ratSimTotal / simTotal
    
    
    def svdEst(dataMat, user, simMeas, item):
        """
        另一种预测评分的方法:基于 SVD 的评分估计
    
        dataMat - 每行是一个用户,每列是该用户对某物品的评分
        user - 要预测的用户
        item - 要预测的物品
        simMeas - 用于计算相似度的函数,ecludSim、pearsSim、cosSim 中的一个
        """
        n = np.shape(dataMat)[1]
    
        simTotal = 0.0
        ratSimTotal = 0.0
    
        # np.linalg.svd(dataMat) 求解 dataMat 的奇异值矩阵
        U, Sigma, VT = np.linalg.svd(dataMat)
    
        # 将 Sigma 转换为只有对角线有值的 r 阶矩阵
        # 这里直接取 4 个
        # Sigma 是有排好序的,正常应该取前 r 个,使其平方和大于90%,或固定一个比较大的数值
        # 然后 dataMat(m,n) ≈ U(m,r) * Sig(r,r) * VT(r,n)
        Sig4 = np.mat(np.eye(4) * Sigma[:4])
    
        # xformedItems 维度是 (n*r),通过转换只保留 r 个用户的所有评分,实现了降维,减少了数据量
        # 是不是也可以保留所有用户的 r 个评分?是不是可以用 VT 映射到另一个空间
        xformedItems = dataMat.T * U[:, :4] * Sig4.I
    
        # 遍历所有物品
        for j in range(n):
            # 取 user 对 j 的评分
            userRating = dataMat[user, j]
    
            # 没评分则跳过
            if userRating == 0 or j == item:
                continue
    
            # 计算 r 个用户对 j 和 item 的评分的相似度
            similarity = simMeas(xformedItems[item, :].T, xformedItems[j, :].T)
    
            # 累加相似度
            simTotal += similarity
    
            # 累加 user 对 j 的评分与相似度的乘积
            ratSimTotal += similarity * userRating
    
        if simTotal == 0:
            return 0
        else:
            # 预测 user 对 item 的评分,计算方法类似 (a1*x1+a2*x2+...+an*xn)/(x1+x2+...+xn) 其中 xi 是 i 和 item 的相似度,ai 是 user 对 i 的评分
            return ratSimTotal / simTotal
    
    
    



    相关文章

      网友评论

          本文标题:机器学习:协同过滤

          本文链接:https://www.haomeiwen.com/subject/fkxoshtx.html