2_基于物品的协同过滤方法

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

1 直观描述

基于物品的协同过滤方法,简单来说就是:通过分析历史数据发现,很多人的购物清单里同时存在啤酒与尿布,那么,对于某一个购买了尿布的客户,我们将啤酒推荐给他。这里我们可以再思考一个问题,就是将尿布推荐给买了啤酒的客户是否合理呢?

2 基于物品协同过滤的步骤

⑴ 构建物品与物品的同现矩阵,基于同现矩阵计算物品之间的相似度矩阵。

\omega_{ij} =\frac{同时喜欢物品i和物品j的用户数}{喜欢物品i的用户数乘以喜欢物品j的用户数,再对乘积开根号}

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

给单个用户进行推荐,自然需要遍历一下他所评价过的物品。该用户对任意一个物品 j 的评分预测值为:

        \sum_{i}(该用户给其操作过的物品i的评分*物品j与物品i的相似度)

但是这样需要对所有物品都计算一次,计算量太大。

我们可以定义一个近邻物品数 k 。遍历一下该用户所有操作过的物品 i ,我们只对与物品 i 相似度最高的 k 个物品进行评分预测。比如,假设该用户操作过 10 个物品,取 k 的值为 8, 那么我们进行评分预测的物品数为 80 个(假设这里面没有出现重复的物品)。如果出现重复的物品,那么我们实际预测的物品数将小于 80。用字典数据类型比较容易解决重复的问题。

3 物品相似度的计算

①我们需要统计出每个物品被多少用户喜欢,即喜欢该物品的用户数。

②我们还需要计算出同现矩阵,即同时喜欢物品 i 和物品 j 的用户数。

根据①和②,我们便可以计算物品之间的相似度了。

下面我们写一个函数来实现这个功能。

def  item_similarity(user_dict):

        item_count = dict()        # 用来保存喜欢某物品的用户数

        count = dict()        # 同现矩阵,用来保存同时喜欢物品 i 和物品 j 的用户数

        # 下面我们遍历user_dict中的所有用户,来获得①和②两个步骤所需要的数据

        for user, user_item in user_dict.items():

                for i in user_item.keys():    # 这里仅计数,没利用上user_item.values()数据

                        item_count.setdefault( i, 0)

                        if  user_dict[user] [ i ]  > 0.0:

                                item_count[ i ] += 1

                        for j in user_item.keys():

                                if  user_dict[user] [ i ]  > 0.0  and  user_dict[user] [ j ]  > 0.0  and  i != j:

                                        count[ i ][ j ] +=1

        # 下面基于同现矩阵计算相似度矩阵

        similarity = dict()        # 用来保存物品间的相似度

        for  i, i_itemsimilar_num  in count.items():

                similarity.setdefault( i, {} )

                for j , num in i_itemsimilar_num.items():

                        similarity[ i ].setdefault( j , 0)

                        similarity[ i ][ j ] = num / math.sqrt( item_count[ i] * item_count[ j ])

        return similarity

4 预测评分的过程

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

然后,对于item_of_thisuser里的各个键(即各个物品),我们通过similarity字典找出与其最相似的 k 个物品,最后将这 k * num_of_thisuser 个物品的预测评分去排序(假设任意两个键对应的 2k 个物品中不存在重复的)。

以上思路很简单,下面我们通过一个函数来实现一下。

def prediction(thisuser, k=8):

        result = dict()    # 用来保存各个物品的评分

        for i, score in item_of_thisuser.items():

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

                for j, wij in sort_similarity[0:k]:

                        if j in score in item_of_thisuser:

                                continue    # 对于已经评分过的物品,没必要对其计算预测评分了

                        result.setdefault( j, 0)

                        result[ j ] += score * wij

        return result     # 此处先不对result里的物品按预测评分排序

上一篇下一篇

猜你喜欢

热点阅读