基于物品的协同过滤算法

Scroll Down

基于物品的协同过滤

基于物品协同过滤算法的两个步骤

  1. 找到和用户喜欢的物品
  2. 根据用户喜欢的物品相类似的物品进行推荐

找到相似物品的方案

方案1(余弦相似度)


N(i)是喜欢物品i的用户数量,N(j)是喜欢物品j的用户数量

    /**
     * 夹角余弦
     * @param aList
     * @param bList
     * @return
     */
    @Override
    public double getDistance(ArrayList<Double> aList, ArrayList<Double> bList) {
        double m_ab = 0 ;           //XY的乘积和
        double m_a = 0;             //X的平方和
        double m_b = 0;             //Y的平方和
        for (int i=0;i<aList.size();i++)
        {
            m_ab+=aList.get(i)*bList.get(i);
            m_a+=Math.pow(aList.get(i),2);
            m_b+=Math.pow(bList.get(i),2);
        }
        return (m_ab)/(Math.sqrt(m_a)*Math.sqrt(m_b));
    }

方案2(IUF)


这个公式惩罚了活跃度高的用户对相似度的影响,因为这个用户如果对多样东西都喜欢,那么这个用户对物品的相似度贡献就意义不是那么大。

/**
     * 改进相似度计算
     * @param aList
     * @param bList
     * @param inverted 用户-物品倒排表
     * @return
     */
    private double getAdvancedSimilarity(ArrayList<Double> aList,ArrayList<Double> bList,ArrayList<HashSet<Integer>> inverted)
    {
        double result=0;
        double a=0;
        double b=0;
        for (int i=0;i<aList.size();i++)
        {
            if (!aList.get(i).equals(0.0))
                a+=1;
            if (!bList.get(i).equals(0.0))
                b+=1;
            if (aList.get(i).equals(bList.get(i))&&!aList.get(i).equals(0.0))
                result+=1/Math.log(1+ inverted.get(i).size());
        }
        if (a*b==0)
            return 0.0;
        return result/(Math.sqrt(a*b));
    }

进行推荐的步骤

  1. 建立倒排表 (用户-物品)
  2. 进行相似度矩阵的计算
  3. 计算用户对物品可能的兴趣
  4. 选取兴趣高的进行推荐

用户对物品的兴趣用如下公式进行表示:

S(j,k) 是与 j 最相似的 k 个物品的集合
用户 u 对 j 的兴趣就是,与 j 相似度最高的前 k 个物品且用户喜欢的物品中,j 和用户喜欢物品的相似度和用户对用户喜欢的物品的喜欢程度(兴趣)的乘积。
和用户喜欢的物品相似度较高的物品将会更容易被推荐到。

def recommend(self, user, k=8, nitems=40):
    result = dict()
    u_item = self.trainData.get(user, {})
    for i, pi in u_items.items():
        for j, wj in sorted(self.items_sim[i].items(), key = lambda x: x[1], reverse = True)[0:k]
            if j in u_items:
                continue;
            result.setdefault(j, 0)
            result[j] += pi * wj
    return dict(sorted(result.items(), key=lambda x: x[1], reverse=True)[0:nitems])

结果评估

推荐结果中推荐的物品都具有较高的相似度,这是itemCF的特点,但涉及相似度计算较多,计算速度较 UserCF 会相对慢许多