item-based CF
给用户推荐那些和他们之前喜欢的物品相似的物品。item-based CF并不是利用物品的内容属性计算物品之间的相似度,主要是通过分析用户的行为记录计算物品间的相似度。
算法步骤
(1)计算物品之间的相似度
(2)根据物品的相似度和用户的历史行为,给用户生成推荐列表
w
i
j
=
∣
N
(
i
)
∩
N
(
j
)
∣
∣
N
(
i
)
∣
w_{ij}=\frac{|N(i)\cap N(j)|}{|N(i)|}
wij=∣N(i)∣∣N(i)∩N(j)∣
其中
∣
N
(
i
)
∣
|N(i)|
∣N(i)∣是喜欢物品
i
i
i的用户数,
∣
N
(
i
)
∩
N
(
j
)
∣
|N(i)\cap N(j)|
∣N(i)∩N(j)∣是同时喜欢物品
i
i
i和物品
j
j
j的用户数。喜欢物品
i
i
i的用户里,有多少比例的用户也喜欢物品
j
j
j。但如果物品
j
j
j很热门,即很多人都喜欢,则
w
i
j
w_{ij}
wij就会很大,接近1;即任何物品都会和热门的物品有很大的相似度,所以添加惩罚物品
j
j
j的权重
w
i
j
=
∣
N
(
i
)
∩
N
(
j
)
∣
∣
N
(
i
)
∣
∣
N
(
j
)
∣
w_{ij}=\frac{|N(i)\cap N(j)|}{\sqrt{|N(i)||N(j)|}}
wij=∣N(i)∣∣N(j)∣∣N(i)∩N(j)∣
用户-物品倒排表
对每个用户建立一个包含他”喜欢的物品的列表“,然后对每个用户,将他”喜欢的物品的列表“中的物品两两在共现矩阵
C
C
C中加1。
对每个用户”喜欢的物品的列表“建立”物品两两对应出现矩阵“,最终将每个用户的”物品两两对应出现矩阵“相加得到共现矩阵
C
C
C,
C
[
i
]
[
j
]
C[i][j]
C[i][j]表示同时喜欢物品
i
i
i和物品
j
j
j的用户数。
import math
def ItemSimilarity(train):
"""
:param train: user-item matrix
:return: W: similarity matrix
"""
#calculate co-rated users between items
C=dict()
N=dict()
for u, items in train.items():
for i in items:
#################
if i not in N:
N[i] = 0
#################
N[i] += 1
for j in items:
if i == j:
continue
#################
if i not in C:
C[i] = dict()
if j not in C[i]:
C[i][j]=0
#################
C[i][j] += 1
#calculate final similarity matrix W
W=dict()
for i, related_items in C.items():
for j, cij in related_items.items():
#################
if i not in W:
W[i] = dict()
if j not in W[i]:
W[i][j] = 0
#################
W[i][j] = cij/math.sqrt(N[i]*N[j])
return W
#test:
train={'A':{'a','b','d'},
'B':{'b','c','e'},
'C':{'c','d'},
'D':{'b','c','d'},
'E':{'a','d'}}
print(ItemSimilarity(train))
#Output:
{'a': {'b': 0.4082482904638631, 'd': 0.7071067811865475},
'b': {'a': 0.4082482904638631, 'd': 0.5773502691896258, 'c': 0.6666666666666666, 'e': 0.5773502691896258},
'd': {'a': 0.7071067811865475, 'b': 0.5773502691896258, 'c': 0.5773502691896258},
'c': {'b': 0.6666666666666666, 'e': 0.5773502691896258, 'd': 0.5773502691896258},
'e': {'b': 0.5773502691896258, 'c': 0.5773502691896258}}
用户u对物品j的兴趣【用户u对物品i的兴趣;物品i和物品j的相似性】
p
u
j
=
∑
i
∈
N
(
u
)
∩
S
(
j
,
K
)
w
j
i
r
u
i
p_{uj}=\sum\limits_{i\in N(u)\cap S(j,K)}w_{ji}r_{ui}
puj=i∈N(u)∩S(j,K)∑wjirui
其中
N
(
u
)
N(u)
N(u)是用户
u
u
u喜欢的物品集合,
S
(
j
,
K
)
S(j,K)
S(j,K)是和物品
j
j
j最相似的
K
K
K个物品的集合,
w
j
i
w_{ji}
wji是物品
j
j
j和物品
i
i
i的相似度,
r
u
i
r_{ui}
rui是用户
u
u
u对物品
i
i
i的兴趣。即,和”用户历史上感兴趣的物品“越相似的物品,在用户的推荐列表里越有可能排名靠前。
from operator import itemgetter
def Recommendation(train, user_id, W, K):
"""
:param train: user-item matrix
:param user_id: user id
:param W: similarity matrix
:param K: number of similar items
:return: recommendation list in order
"""
#give final recommendation list
rank=dict()
ru=train[user_id] #user_id喜欢的物品集
for i in ru: #user_id喜欢的物品i
if i not in W:
continue
for j, wj in sorted(W[i].items(), key=itemgetter(1), reverse=True)[0:K]: #与物品i相似度最大的K个物品
if j in ru: #如果与物品i 相似度在前K个位置的物品j 在user_id原本喜欢的物品集里
continue
#################
if j not in rank:
rank[j] = 0
#################
rank[j] += wj
return rank
#test:
train={'A':{'a','b','d'},
'B':{'b','c','e'},
'C':{'c','d'},
'D':{'b','c','d'},
'E':{'a','d'}}
W=ItemSimilarity(train)
print(Recommendation(train, 'A', W, 1))
print(Recommendation(train, 'A', W, 3))
#Output:
{'c': 0.6666666666666666}
{'c': 1.2440169358562925, 'e': 0.5773502691896258}
#即遍历指定用户喜欢的每个物品的/前K个相似物品
扫码关注公众号:瑞行AI,欢迎交流AI算法、数据分析等技术,提供技术方案咨询和就业指导服务!