ItemCF的Python实现

ItemCF的Python实现,第1张

前言

在上一篇文章中,介绍了UserCF的实现思路。趁热打铁,这里再介绍一下ItemCF的实现思路。
水平有限,不妥之处还希望大佬多多指正。
数据集与完整代码:https://github.com/ziyuan0014/rec_itemCF

实现思路 数据

本案例所用数据同UserCF的一致,数据样式如下表所示:

user_idcontent_idscorets
0115874965758
1123876893171
2134878542960
3143876893119
4153889751712

评分矩阵的计算方法同样不变,这里不再进行赘述。

基于物品的协同过滤

根据ItemCF的基本思想,算法要做的事情就是给用户推荐那些和他们之前喜欢的物品相似的物品。在本案例中,整个实现过程同样有三个步骤:

步骤一:计算用户之间的相似度

这里用的依然是余弦相似度:

item_sim_matrix = np.zeros((contentNum,contentNum))
idx = 0
while idx < len(rating):
    idy = idx + 1
    while idy < len(rating):
        item_sim_matrix[idx,idy] = cos_dist(rating[idx],rating[idy])
        idy = idy +1
    idx = idx + 1

如果依然用之前所用的评分矩阵计算方法,这一步就无需进行转置,直接依次计算即可。在这一步中值得一提的是:ItemCF算法并不是直接根据物品本身的属性来计算相似度,而是依然通过用户对物品的行为来计算物品之间的相似度。
在这一步中,本案例采用的这种计算方法是默认所有用户对物品的贡献(影响)是相同的,因而有很大的提升空间,这里再安利一篇文章:《ItemCF的演进:狭义 VS 广义》,其中提及了相似度矩阵求的改进,感兴趣的话可以尝试一下,链接:https://zhuanlan.zhihu.com/p/377772010。

步骤二:返回相似物品

选出sim_item_max_len个和物品i最相似的物品,代码如下:

sim_user_dict = {}
sim_user_max_len = 5 # 定义给每个人最大的相似用户数量
for i in range(userNum):
    temp_series = pd.DataFrame(user_sim_matrix[i],columns=['user_factorize_'+str(i)])
    sim_user_index = temp_series.sort_values(by = 'user_factorize_'+str(i),ascending = False)[0:sim_user_max_len].index.tolist()
    for user_index in sim_user_index:
        if temp_series.iloc[user_index].values == 0:
            sim_user_index.remove(user_index)
    sim_user_dict[i] = sim_user_index
real_sim_item_dict = {}
    real_sim_item_socre_dict = {}
    sim_item_max_len = 20
    for i in range(contentNum):
        temp_series = pd.DataFrame(item_sim_matrix[i],columns=['item_factorize_'+str(i)])
        sim_item_index = temp_series.sort_values(by = 'item_factorize_'+str(i),ascending = False)[0:sim_item_max_len].index.tolist()
        sim_item_score = list(temp_series.iloc[sim_item_index].values.reshape(-1))
        for j in list(range(len(sim_item_score)))[::-1] : # 从后往前遍历
            if sim_item_score[j] == 0:
                sim_item_index.pop(j)
                sim_item_score.pop(j)
        real_item_index = []
        for item_factorize_id in sim_item_index:
            real_item_index.append(reGetContentId(pd_factorize_data,item_factorize_id))
        real_sim_item_dict[reGetContentId(pd_factorize_data,i)] = real_item_index
        real_sim_item_socre_dict[reGetContentId(pd_factorize_data,i)] = sim_item_score

整体思路依然是先排序取最大的几个index,然后再把其中相似度为0的去掉。需要注意的是,这里在对list进行遍历除0的时候,由于是采用的索引,需要从后往前遍历,保证list.pop()后list与索引之间还能对上号。

步骤三:根据用户的浏览情况进行推荐

代码

user_rec_dict = {}
user_rec_score_dict = {}
userNum = pd_factorize_data['user_factorize_id'].max() + 1
for user_factorize_id in range(userNum):
    user_data = pd_factorize_data[pd_factorize_data['user_factorize_id'] == user_factorize_id]
    user_id = reGetUserId(user_data,user_factorize_id)
    user_list = []
    user_score_list = []
    for content in user_data['content_id'].values:
        item_sim = real_sim_item_dict.get(content)
        score = user_data[user_data['content_id']==content]['score'].values[0]
        item_sim_score = real_sim_item_socre_dict.get(content)
        for i in range(len(item_sim_score)):
            rec_score = score * item_sim_score[i]
            if rec_score > 0 and item_sim[i] not in user_list:
                user_score_list.append(rec_score)
                user_list.append(item_sim[i])
        
    if len(user_list) >0 :
        user_rec_dict[user_id] = user_list
        user_rec_score_dict[user_id] = user_score_list

这里还是定义了两个dict,一个用来存储为每个用户进行推荐的内容id,另一个则用来存储相应内容id的推荐分数。关于不同item的rec_score,这里只取了第一次出现的相似item的score,但是这个分数却并不一定是最高的rec_score,举个例子:用户u喜欢A(5)和B(4)两个物品,这两个物品中的相似物品都有C,而item_sim_score(A,C)=0.2、item_sim_score(A,B)=0.4,而 5 ∗ 0.2 < 4 ∗ 0.4 5*0.2<4*0.4 50.2<40.4。一个比较理想的策略是,先把所有的计算结果都存下来,然后再根据相应的item取分数最高的作为rec_score。
同样的数据集,相比UserCF,这一步943个用户大概跑了两分钟就完成啦。

至此整个算法实现完毕,后续根据项目需求灵活取用即可。

尾言

总的来说,UserCF和ItemCF都属于比较简单的算法,非常适合作为推荐系统的入门,但也确实存在着很多的问题,除了文中提到的相似度计算方法外,还有数据稀疏、头部效应等,因此后续同样出现了很多基于CF改进的推荐算法的研究。
花时间认真复现一遍,打下基础,并在这个过程中对各种细节进行深入了解,还是很值得的。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/791864.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-05
下一篇 2022-05-05

发表评论

登录后才能评论

评论列表(0条)

保存