3_基于用户的协同过滤方法

2020-11-24  本文已影响0人  蓝冻

1 直观描述

用户A有几个“关系很好”的朋友 B、C、D,通常B或C或D买了什么东西的话,A也要跟着买。昨天,B新买了一个物品 g ,而用户A之前也从没见过物品 g ,那么,购物平台就将 g 推荐给A。

2 基于用户协同过滤的步骤

⑴ 计算用户间的相似度。

    \omega_{uv} =\frac{同时被用户u和用户v喜欢的物品数}{用户u喜欢的物品数乘以用户v喜欢的物品数,再对乘积开根号}

⑵ 预测某一用户对物品集中他尚未进行评分的物品的评分,并依据计算出来的评分高低来进行推荐。也可以先对所有物品进行评分预测,然后剔除掉已评分的物品,对剩下的物品进行排序。

3 用户相似度的计算

用两个for循环遍历user_dict中的用户,通过集合的交集运算,很容易得到同时被用户u和用户v喜欢的物品数,至于每个用户喜欢的物品数,通过len()函数很容易得到,于是就得到所有的\omega_{uv} 了。

上面这种做法将会把每两个用户之间的相似度都算一遍,计算量太大而且也没必要,因为在实际场景下,与用户A“关系很好”的朋友的数量通常是有限的。我们将用户A “关系很好 ”的那几个朋友找出来并计算他们与A的相似度就行了。

这就可以用上倒排表了。所谓倒排表,指的是从用户评分文件转换而来的物品用户倒排表。设倒排表为字典 T,则 T 中记录的是各个物品被哪些用户操作过。之后我们只计算操作过同一物品的不同用户之间的相似度就行了,计算的方法就是:对一个物品,用for循环遍历两遍其用户集。当然,我们还需要把所有物品给遍历一遍,这样才能累加得到同时被用户u和用户v喜欢的物品数。

下面我们定义一个函数实现用户相似度的计算。

def  user_similarity( user_dict ):

        # 构建倒排表

        item_users = dict()

        for u, u_items in user_dict.items():

                for i in u_items.keys():

                        item_users.setdefault( i, set() )

                        if user_dict[u][i] > 0.0:

                                item_users[ i ].add(u)    # 把用户u加入到物品 i 的用户集合中去

        # 上面的过程得到了倒排表 item_users

        # 构建用户在物品集上的同现矩阵,只对出现在同一个用户集里的两个用户进行计算

        user_itemcount = dict()    # 记录每个操作的物品数,后面要当做分母

        count = dict()   # 同现矩阵

         for i , i_users in item_users.items():

                for u in i_users:

                        user_itemcount.setdefault( u, 0 )

                        user_itemcount[u] += 1

                        count.setdefault(u, {} )

                        for v in i_users:

                                count[u].setdefault( v, 0 )

                                if u == v:

                                        continue

                                count[u][v] += 1 / math.log( 1 + len(i_users) )  

                                # len(i_users)表示操作过物品 i 的用户集里用户的数目,此处对热门物品进行了惩罚

        similarity = dict()    # 记录用户相似度

        for u , u_users in count.items():

                similarity.setdefault(u, {})

                for v, v_u in  u_users.items():

                        if u == v:

                                continue

                        similarity[u].setdefault(v, 0.0)

                        similarity[u][v] = v_u / math.sqrt( user_itemcount [u] * user_itemcount[v] )

        return similarity

4 预测评分的过程

我们可以定义一个近邻用户数 k 。在对某个用户进行推荐时,我们把与该用户 “关系最好”的其它 k 个用户所操作过的物品全部找出来,并从中剔除掉该用户已经操作过的物品,然后只对剩下的物品进行评分预测。

我们先找出该用户评价过的所有物品,假设保存在 item_of_thisuser字典里,字典的键为各个评价过的物品。事实上, item_of_thisuser 很容易从原始评分文件user_dict中提取出来。

下面我们定义一个函数实现评分预测的过程,暂时不考虑最终的排序问题。

def prediction(thisuser, k=8):

        result = dict()

        sort_similarity = sorted( similarity[ thisuser ].items(), key=lambda x: x[1], reverse=True)

        for v, wuv in sort_similarity[0: k]:

                for i, r_vi in user_dict[v].items():

                        if i in item_of_thisuser:

                                continue

                        result.setdefault(i, 0)

                        result[i] += r_vi * wuv

        return result

5 用户协同与物品协同的比较

从推荐场景而言,在电子商务、电影网站和图书网站等领域,用户数量远大于物品数量,且物品的数量更新速度并不快,可以考虑物品协同的方法。

对于新闻、博客等类似于信息流的领域,由于内容更新频率非常高,且内容很容易过时,可以考虑用户协同的方法。

用户协同更注重社会化因素,而物品协同更注重个性化因素。

上一篇下一篇

猜你喜欢

热点阅读