前言
从今天开始跟着视频学习推荐系统,顺便将CSDN作为备忘录进行记录,也能起到督促自己的作用。也希望这个笔记能够帮助到更多的人。
在介绍利用相似度做推荐前,先创建数据,如创建下列用户的物品喜好表格数据:
users = ['user1','user2','user3','user4','user5']
items = ['item A','item B','item C','item D','item E']
datasets = [[1,0,1,1,0],
[1,0,0,1,1],
[1,0,1,0,0],
[0,1,0,1,1],
[1,1,1,0,1],]
import pandas as pd
df = pd.DataFrame(datasets, columns=items, index=users)
print(df)
得到:
/ | item A | item B | item C | item D | item E |
---|---|---|---|---|---|
user1 | 1 | 0 | 1 | 1 | 0 |
user2 | 1 | 0 | 0 | 1 | 1 |
user3 | 1 | 0 | 1 | 0 | 0 |
user4 | 0 | 1 | 0 | 1 | 1 |
user5 | 1 | 1 | 1 | 0 | 1 |
Jaccard相似度
公式
适合计算bool值 {0,1} 的向量间的相似度(稠密数据)
s
i
m
(
a
,
b
)
=
a
∩
b
a
∪
b
sim(a,b)=\frac{a\cap b}{a\cup b}
sim(a,b)=a∪ba∩b
示例
1.计算jaccard相似度
1.1)基于物品(item-based):计算物品A与物品B之间的jaccard相似度
from sklearn.metrics import jaccard_score
#比较对象可以是list, tuple, pd.Series, np.array等等。。
print(jaccard_score(df['item A'], df['item B']))
输出 0.2
1.2)基于用户(user-based):计算用户2与用户3之间的jaccard相似度
from sklearn.metrics import jaccard_score
print(jaccard_score(df.loc['user2'], df.loc['user3']))
输出 0.25
1.3)计算用户两两之间的jaccard相似度
from sklearn.metrics.pairwise import pairwise_distances
df.dtype = bool #需要制定DataFrame的dtype,否则下一步会报错
# jaccard相似度 = 1 - jaccard距离
user_simi = 1 - pairwise_distances(df, metric="jaccard") # 用户间相似度
# item_simi = 1 - pairwise_distances(df.T, metric="jaccard") # 物品间相似度
user_simi = pd.DataFrame(user_simi, columns=users,index=users)
print('用户向量两两间相似度:', user_simi)
得到:
/ | user1 | user2 | user3 | user4 | user5 |
---|---|---|---|---|---|
user1 | 1.000000 | 0.50 | 0.666667 | 0.2 | 0.4 |
user2 | 0.500000 | 1.00 | 0.250000 | 0.5 | 0.4 |
user3 | 0.666667 | 0.25 | 1.000000 | 0.0 | 0.5 |
user4 | 0.200000 | 0.50 | 0.000000 | 1.0 | 0.4 |
user5 | 0.400000 | 0.40 | 0.500000 | 0.4 | 1.0 |
2.利用jaccard相似度做推荐
为用户a寻找相似用户B,将这些相似用户B的喜好作为用户a的推荐 (去重)
2.1)取前2个最相似的用户
top2_users = {}
for i in user_simi.index:
df_ = user_simi.loc[i].drop([i]) # 移除自身
df_sort = df_.sort_values(ascending=False)
top2 = list(df_sort.index[:2])
top2_users[i] = top2
print(top2_users)
得到:
{‘user1’: [‘user3’, ‘user2’],
‘user2’: [‘user4’, ‘user1’],
‘user3’: [‘user1’, ‘user5’],
‘user4’: [‘user2’, ‘user5’],
‘user5’: [‘user3’, ‘user4’]}
2.2)为用户推荐最相似用户喜欢的物品
re_results = {}
for user, sim_users in top2_users.items():
re_result = []
for sim_user in sim_users: # 遍历用户的相似用户
# 获得相似的用户的喜好
re_result.extend(df.loc[sim_user].index[df.loc[sim_user] == 1].tolist())
re_result = set(re_result) # 剔除重复项
# 剔除用户本身的喜好
re_result -= set(df.loc[user].index[df.loc[user] == 1].tolist())
re_results[user] = re_result
print(re_results)
得到:
{‘user1’: {‘item E’},
‘user2’: {‘item C’, ‘item B’},
‘user3’: {‘item E’, ‘item D’, ‘item B’},
‘user4’: {‘item A’, ‘item C’},
‘user5’: {‘item D’}}
Pearson相似度(相关系数)
可看成是减去了平均值的余弦相似度,适合连续数据的比较。取值范围为 [ 1 , − 1 ] [1,-1] [1,−1],正数表示正相关,负数表示负相关,0表示无关(稠密数据)
公式
r = ∑ i = 1 n ( x i − x ˉ ) ( y i − y ˉ ) ∑ i = 1 n ( x i − x ˉ ) 2 ∑ i = 1 n ( y i − y ˉ ) 2 r = \frac{\sum_{i=1}^n (x_i-\bar{x})(y_i-\bar{y})}{\sqrt{\sum_{i=1}^n (x_i-\bar{x})^2}\sqrt{\sum_{i=1}^n (y_i-\bar{y})^2}} r=∑i=1n(xi−xˉ)2∑i=1n(yi−yˉ)2∑i=1n(xi−xˉ)(yi−yˉ)
示例
pandas中自带了pearson相关系数的计算。以上述pandas表格为例:
1.计算pearson相似度
user_simi = df.T.corr() # 获得节点间pearson相似度(基于用户)
item_simi = df.corr() # 获得物品间pearson相似度(基于物品)
2.利用pearson相似度做推荐
取与用户i相似度最高的前2个用户j,k,设
r
i
j
r_{ij}
rij表示用户i和用户j之间的pearson相似度,
s
i
a
s_{ia}
sia表示用户i对商品a的评分,则给用户i可能给商品a的评分为:
p
r
e
d
(
i
,
a
)
=
r
i
j
∗
s
j
a
+
r
i
k
∗
s
k
a
r
i
j
+
r
i
k
pred(i,a) = \frac{r_{ij}*s_{ja}+r_{ik}*s_{ka}}{r_{ij}+r_{ik}}
pred(i,a)=rij+rikrij∗sja+rik∗ska
基于(二分)图的相似度
通过用户(A,B,C,D)之间的路径数、路径长度和经过的用户数来评价两个用户之间的相关性(稀疏数据)
基于模型的算法
基于矩阵分解
r
⟼
f
u
s
e
r
×
f
m
o
v
i
e
s
R
n
×
m
⟼
R
n
×
k
×
R
k
×
m
r \longmapsto f_{user} \times f_{movies} \\ \mathbb{R}^{n\times m} \longmapsto\mathbb{R}^{n\times k}\times \mathbb{R}^{k\times m}
r⟼fuser×fmoviesRn×m⟼Rn×k×Rk×m
其中
f
u
s
e
r
f_{user}
fuser(
R
n
×
k
\mathbb{R}^{n\times k}
Rn×k)为用户矩阵,
f
m
o
v
i
e
s
f_{movies}
fmovies(
R
k
×
m
\mathbb{R}^{k\times m}
Rk×m)为物品矩阵,k可以看成是影响用户评分的因素。
因此可以理解成:
用户矩阵:k种因素对用户的重要性占比
物品矩阵:物品的k种因素的大小
因此,用户i对某件商品a的评分
s
c
o
r
e
=
f
u
s
e
r
i
,
:
×
f
m
o
v
i
e
s
:
,
a
score = f_{user}^{i,:}\times f_{movies}^{:,a}
score=fuseri,:×fmovies:,a
ALS(交替最小二乘法)
随机初始化并固定 f u s e r f_{user} fuser,利用公式计算 f m o v i e s f_{movies} fmovies;再固定 f m o v i e s f_{movies} fmovies,计算f_{user};不断迭代直至收敛。
公式
f
u
s
e
r
=
arg
min
w
∈
R
d
∑
(
r
i
j
−
w
T
f
m
o
v
i
e
s
)
2
+
λ
∥
w
∥
2
2
f_{user}=\mathop{\arg\min}\limits_{w\in \mathbb{R^d}}\sum(r_{ij}-w^Tf_{movies})^2+\lambda \|w\|_2^2
fuser=w∈Rdargmin∑(rij−wTfmovies)2+λ∥w∥22
同理:
f
m
o
v
i
e
s
=
arg
min
w
∈
R
d
∑
(
r
i
j
−
w
T
f
u
s
e
r
)
2
+
λ
∥
w
∥
2
2
f_{movies}=\mathop{\arg\min}\limits_{w\in \mathbb{R^d}}\sum(r_{ij}-w^Tf_{user})^2+\lambda \|w\|_2^2
fmovies=w∈Rdargmin∑(rij−wTfuser)2+λ∥w∥22