基于用户的协同过滤算法(UserCF)
基于用户的协同过滤算法是通过用户的历史行为数据发现用户对物品的喜好,并对这些喜好进行度量和打分,根据不同用户对相同物品的偏好计算用户之间的相似度,在有相同喜好的用户间进行推荐。
步骤:
- 找到与目标用户兴趣相似的用户集合
- 找到这个集合中用户喜欢的并且目标用户没有购买过的物品推荐给目标用户
优点:
- 能够在用户间相互协助,根据用户对物品的打分的相似性对用户进行分类
- 所有用户都能从邻居用户的反馈评价中得意
- 容易挖掘目标用户潜在的新兴趣
缺点:
- 稀疏性:一个大型的电商平台有非常多的物品,用户购买的物品很少,不同用户之间买的物品重叠率较低,导致无法找到目标用户的邻居。
- 冷启动问题:在一个新物品首次出现的时候,没有用户对它进行打分,无法对其进行预测和推荐,而且在新物品出现早期,用户打分少,推荐准确率不高
- 特殊用户的喜好和任何一类群体都不同,无法找到目标用户的邻居用户进行协同推荐,用户是“善变”的,用户喜好可能会发生变化
基于物品的协同过滤算法(ItemCF)
基于物品的协同过滤给用户推荐那些和用户之前喜欢的物品相似的物品,ItemCF不利用物品的内容相似计算物品的相似度,它是通过分析用户行为记录计算物品的相似度,物品A和B相似是因为喜欢物品A的用户也喜欢物品B。
步骤:
- 计算物品之间的相似度
- 根据物品的相似度和用户历史行为给用户生成推荐列表
优点:
- 计算性能高,通常用户数量远大于物品数量
- 可预先计算保留,物品不“善变”
协同过滤中冷启动问题
- 用户冷启动:新用户因为没有在物品上留下行为数据,自然无法得知用户的喜好,不能给新用户推荐物品,这时一般需要借助用户的背景资料,或者引导用户选择,或者暂时用热门启动替代个性化推荐(给用户推荐排行榜单),在线推荐系统可以做到在用户产生行为数据后立马更新推荐列表。
- 物品冷启动:对于一个物品推荐类似物品,因为新物品还没有用户行为数据,自然也就没办法通过协同过滤的方式进行推荐,一般对物品的描述进行文本分析,或者采用主题模型,或者打标签,或者推荐排行榜单。
两种推荐算法的比较
基于用户的协同过滤算法实现
import numpy as np
class Recommand():
def __init__(self, users):
"""
初始化
"""
self.users = users
def pearson(self, username, user):
"""
:Input: 目标用户和其他用户
:return: 目标用户与其他用户的皮尔森系数
"""
x = []
y = []
for movie, score in self.users[username].items():
if movie in self.users[user].keys():
x.append(self.users[username][movie])
y.append(self.users[user][movie])
x = np.array(x)
y = np.array(y)
sum_xy = ((x-x.mean())*(y-y.mean())).sum()
sum_x = np.sqrt(((x-x.mean())*(x-x.mean())).sum())
sum_y = np.sqrt(((y-y.mean())*(y-y.mean())).sum())
return sum_xy/(sum_x*sum_y)
def nearstUser(self, username, k):
"""
:Input: 目标用户和最近邻个数
:return: 排好序的前k个邻居的皮尔森系数
"""
distances = {}
for user in self.users.keys():
if user != username:
distances[user] = self.pearson(username, user) # 计算皮尔森系数
distances = sorted(distances.items(), key=lambda x:x[1], reverse=True) # 排序
return distances[:k]
def recommand(self, username, k):
"""
:Input: 目标用户和最近邻个数
:return: 推荐结果及预测的评分
"""
recommand_list={} # 推荐的电影
s = 0
for user, score in dict(self.nearstUser(username, k)).items(): # 最近的k个用户
s += score
for movies, scores in self.users[user].items(): # 推荐的用户的电影列表
if movies not in self.users[username].keys(): # 当前username没有看过
recommand_list.setdefault(movies, 0)
if movies in recommand_list.keys(): # 添加到推荐列表中
recommand_list[movies] = recommand_list[movies]+score*scores
for k,v in recommand_list.items():
recommand_list[k] = np.round(v/s, 1)
return sorted(recommand_list.items(), key=lambda x:x[1], reverse=True) # 对推荐的结果按照电影评分排序
if __name__=='__main__':
users = {'Lisa Rose': {'Lady in the Water': 2.5, 'Snakes on a Plane': 3.5, 'Just My Luck': 3.0, 'Superman Returns': 3.5, 'You, Me and Dupree': 2.5, 'The Night Listener': 3.0},
'Gene Seymour': {'Lady in the Water': 3.0, 'Snakes on a Plane': 3.5, 'Just My Luck': 1.5, 'Superman Returns': 5.0, 'The Night Listener': 3.0, 'You, Me and Dupree': 3.5},
'Michael Phillips': {'Lady in the Water': 2.5, 'Snakes on a Plane': 3.0, 'Superman Returns': 3.5, 'The Night Listener': 4.0},
'Claudia Puig': {'Snakes on a Plane': 3.5, 'Just My Luck': 3.0, 'The Night Listener': 4.5, 'Superman Returns': 4.0, 'You, Me and Dupree': 2.5},
'Mick LaSalle': {'Lady in the Water': 3.0, 'Snakes on a Plane': 4.0, 'Just My Luck': 2.0, 'Superman Returns': 3.0, 'The Night Listener': 3.0, 'You, Me and Dupree': 2.0},
'Jack Matthews': {'Lady in the Water': 3.0, 'Snakes on a Plane': 4.0, 'The Night Listener': 3.0, 'Superman Returns': 5.0, 'You, Me and Dupree': 3.5},
'Toby': {'Snakes on a Plane': 4.5, 'You, Me and Dupree': 1.0, 'Superman Returns': 4.0}
}
usercf = Recommand(users)
result = usercf.recommand('Toby', 2)
print('为目标用户%s推荐的结果:%s'% ('Toby', result))
为目标用户Toby推荐的结果:[(‘The Night Listener’, 3.0), (‘Lady in the Water’, 2.7), (‘Just My Luck’, 2.5)]