引言
用一百行 Python 代码,入门协同过滤推荐。
数据准备
用户对物品的喜好记录,第一列是用户,第二列是物品。在终端输入:
1 | python3 |
基本概念
偏好矩阵
偏好记录可以转化成偏好矩阵,在 Python 中用 dict 保存:
prefs | item1 | item2 | item3 | item4 | item5 | item6 |
---|---|---|---|---|---|---|
user1 | 1 | |||||
user2 | 1 | 1 | ||||
user3 | 1 | |||||
user4 | 1 | 1 | ||||
user5 | 1 | 1 | ||||
user6 | 1 |
1 | # {'andy': {'霍乱时期的爱情': 1},...} |
偏好相似度(距离函数)
给定两个用户 user1
user2
和偏好向量 [1,0,0,0,0,0]
[1,1,0,0,0,0]
,我们需要定义一个距离函数,返回 0.0~1.0,衡量他们的相似度。距离函数可以选择余弦距离、欧几里得距离、棋盘距离等等,定义不同的距离函数有不同的推荐效果。
这里简单地用 Jaccard 相似性系数,即两个用户感兴趣的书的交集除并集:
1 | def jaccard_distance(prefs, user1, user2): |
举个例子,item5 和 item6 的用户评价向量的 Jaccard 距离 = 1 / 4 = 0.25。
prefs | user1 | user2 | user3 | user4 | user5 | user6 |
---|---|---|---|---|---|---|
item5 | 1 | 1 | 1 | |||
item6 | 1 | 1 |
基于用户的协同过滤(User-CF)
现在我们有了用户的偏好信息,能够衡量任意用户间的相似度,那么,对于 user1
,如何给他推荐物品?
首先,要找出与这个 user1
兴趣相近的用户们,即与 user1
对偏好向量距离相近的用户。然后,找出兴趣相近用户中,最受欢迎的书,推荐给 user1
。
比如对 user4
,发现 user5
的评价距离相近,可以推荐他在读的 item4
给他。
1 | # 找出与 user1 兴趣最相近的用户 user1 -> [(1.0, user3), (0.8, user4), ...] |
输出结果
1 | 用户:jim |
基于物品的协同过滤(Item-CF)
在神奇的数学世界里,我们把偏好矩阵转置,即行列互换,用相同的思想,可以得到一种新的推荐方法 —— 基于物品的协同过滤。
用 User-CF 方法,对于给定用户,根据偏好矩阵,算出兴趣相近的用户;用 Item-CF 方法,对于给定物品,根据偏好矩阵,算出用户评价向量相近的物品,作为推荐。
1 | # prefs[userId][itemId] -> prefs[itemId][userId] |
得到转置后的偏好矩阵:
prefs | user1 | user2 | user3 | user4 | user5 | user6 |
---|---|---|---|---|---|---|
item1 | 1 | 1 | ||||
item2 | 1 | |||||
item3 | ||||||
item4 | 1 | |||||
item5 | 1 | 1 | 1 | |||
item6 | 1 | 1 |
如果一个用户喜欢物品 item5
,可以推荐用户偏好向量距离相近的物品如 item4
和 item6
给这位用户。
1 | def calculate_item_cf(prefs, similarity, n = 10): |
输出结果
1 | 根据 创业维艰 推荐: |
延伸阅读
《集体智慧编程》—— 协同过滤