大纲
- user-based cf
- item-based cf
- item_based 代码实践
- user_based vs. item_based
1.user_based cf
基于用户的协同过滤算法的思路是:找到与该用户有相似兴趣的用户,然后将这些相似用户感兴趣的商品推荐给该用户。因此,基于用户协同过滤算法可以分为2个步骤:
- 寻找和目标用户兴趣相似的用户集合
一般根据用户对商品的评分,计算Jaccard或者余弦相似度来衡量用户之间的兴趣相似度。
Jaccard相似度:
余弦相似度:
- 找到这个集合中的用户喜欢的,且目标用户没有听说过的物品推荐给目标用户。
1.1 用户相似度的改进
用余弦相似度来度量用户之间兴趣相似度过于粗糙,因为两个用户对热门物品采取过相同的行为并不能说明他们兴趣相似,但对于冷门物品才去过相同的行为更能说明他们兴趣的相似度。
2.item_based cf
基于物品的协同过滤算法直接找出目标用户感兴趣的商品,然后将和这些商品相似的商品推荐给目标用户。物品相似度也是通过Jaccard或者余弦相似度来衡量,这里不再赘述。因此,基于物品的推荐的2个步骤:
- 计算物品之间的相似度
- 根据物品相似度与用户的历史行生成推荐列表
3. item_based 代码实践
代码中有些地方用numpy代替dict,可以降低内存,不过仍然有个问题,因为item之间的相似关系可能是稀疏的,但是numpy是密集型,所以也存在空间浪费。
由于user-based和item-based原理一样,因此下面只展示了item-based的代码实践。
item-based cf
# -*- coding:utf-8 -*-
import pandas as pd
import numpy as np
import math
import json
class ItemCF(object):
def __init__(self, fname):
self.fname = fname
self._read_data1(fname)
def _read_data(self, fname):
self.item_users = {}
with open(fname, "r") as fr:
for line in fr:
fields = line.strip().split(",")
device_uid = fields[1]
resblock_id = fields[2]
cnt = fields[3]
self.item_users.setdefault(resblock_id, {})
self.item_users[resblock_id][device_uid] = cnt
# 对物品编号
all_items = self.item_users.keys()
self.item_size = len(all_items)
self.item_vocab = dict([(item, ind) for ind, item in enumerate(all_items)])
self.item_reverse_vocab = np.array(all_items)
def similarity(self):
self.item_popularity = np.zeros(self.item_size)
# 计算浏览物品的用户数
for item, user_info in self.item_users.items():
_item_index = self.item_vocab[item]
self.item_popularity[_item_index] = len(user_info)
# 计算物品相似度
self.item_similarity = np.zeros((self.item_size, self.item_size))
for i in range(self.item_size-1):
_former_item = self.item_reverse_vocab[i]
_former_item_popularity = self.item_popularity[i]
_former_item_users = self.item_users[_former_item].keys()
for j in range(i+1, self.item_size):
_latter_item = self.item_reverse_vocab[j]
_latter_item_popularity = self.item_popularity[j]
_latter_item_users = self.item_users[_latter_item].keys()
common_size = len(set(_former_item_users) & set(_latter_item_users))
sim = float(common_size) / math.sqrt(_former_item_popularity * _latter_item_popularity)
self.item_similarity[i][j] = sim
self.item_similarity[j][i] = sim
def save_model(self, vocab_reverse_fname, sim_fname):
np.save(vocab_reverse_fname, self.item_reverse_vocab)
np.save(sim_fname, self.item_similarity)
4.user_based vs. item_based
对比项 | user_based | item_based |
---|---|---|
性能 | 适合于用户数量较小的场景 | 适用于物品数量明显小于用户数量的场景 |
个性化 | 时效性较强,用户个性化兴趣不太明显的领域 | 长尾物品丰富,用户个性化需求强烈的领域 |
实时性 | 用户的新行为不一定导致推荐结果的立即变化 | 用户的新行为一定会导致推荐结果的实时变化 |
网友评论