《推荐系统笔记(十七)》userCF和itemCF —— 基于领域的推荐

面对用户-物品评分矩阵,我们有一种推荐思路,叫做基于领域的推荐。

什么是itemCF和userCF?可以这样理解,

  • 我喜欢这个商品,那么和这个商品非常类似的其他商品,可能也是我喜欢的,这个是itemCF的思路,推荐和用户喜欢的商品类似的其他商品
  • 我喜欢这个商品,别人也喜欢这个商品,那么我们可能兴趣很相似,那么那人喜欢的其他商品,可能也是我喜欢的,这个是userCF的思路,推荐和用户相似的其他用户喜欢的商品

那么,什么是领域?

  • 对于itemCF而言,领域就是和该商品类似的其他商品,这种度量是商品相似度
  • 对于userCF而言,领域就是和该用户类似的其他用户,这种度量是用户相似度

基于用户-物品评分矩阵 R m × n R_{m\times n} Rm×n,相似度 s i m i l a r i t y similarity similarity如何定义?

这在userCF和itemCF里面定义形式相似但有不同,我们分别来说。

相似度

1. userCF里的相似度

有两种常用的以及一个改进的。我们假设 N ( u ) N(u) N(u)为用户 u u u评分过的物品集合。

1.1 Jaccard相似度

用户 u u u v v v的Jaccard相似度为
w u v = ∣ N ( u ) ∩ N ( v ) ∣ ∣ N ( u ) ∪ N ( v ) ∣ w_{uv}=\frac{|N(u)\cap N(v)|}{|N(u)\cup N(v)|} wuv=N(u)N(v)N(u)N(v)

这里的意思是,两个用户购买的物品越重合,说明两个用户越相似。

1.2 Cosine相似度

用户 u u u和用户 v v v的余弦相似度为
w u v = ∣ N ( u ) ∩ N ( v ) ∣ ∣ N ( u ) ∣ ∣ N ( v ) ∣ w_{uv}=\frac{|N(u)\cap N(v)|}{\sqrt{|N(u)||N(v)|}} wuv=N(u)N(v) N(u)N(v)

当然,也可以直接用评分数据来做,如下
w u v = ∑ i ∈ N ( u ) ∩ N ( v ) r u i r v i ∑ i ∈ N ( u ) r u i 2 ⋅ ∑ i ∈ N ( v ) r v i 2 w_{uv}=\frac{\sum_{i\in N(u)\cap N(v)}r_{ui}r_{vi}}{\sqrt{\sum_{i\in N(u)}r_{ui}^2\cdot\sum_{i\in N(v)}r_{vi}^2}} wuv=iN(u)rui2iN(v)rvi2 iN(u)N(v)ruirvi

其实就是把评分矩阵的第 u u u行的向量提出来,把第 v v v行的向量提出来,求两个向量的夹角的余弦值。

1.3 改进的相似度

对于热门商品,大家都会买,所以并不能体现两个用户有多相似,由于 N ( u ) ∩ N ( v ) N(u)\cap N(v) N(u)N(v)中可能有一大部分为热门商品,我们期望能降低热门商品的影响,可以重写为
N ( u ) ∩ N ( v ) → ∑ i ∈ N ( u ) ∩ N ( v ) 1 l o g ( 1 + N ( i ) ) N(u)\cap N(v)\rightarrow \sum_{i\in N(u)\cap N(v)}\frac{1}{log(1+N(i))} N(u)N(v)iN(u)N(v)log(1+N(i))1

其中, N ( i ) N(i) N(i)为购买过物品 i i i的用户人数。显然,热门商品的购买人数会很大,所以 1 l o g ( 1 + N ( i ) ) \frac{1}{log(1+N(i))} log(1+N(i))1就会小,形成对热门商品的一个惩罚。

改进后的相似度为
w u v = ∑ i ∈ N ( u ) ∩ N ( v ) 1 l o g ( 1 + N ( i ) ) ∣ N ( u ) ∣ ∣ N ( v ) ∣ w_{uv}=\frac{\sum_{i\in N(u)\cap N(v)}\frac{1}{log(1+N(i))}}{\sqrt{|N(u)||N(v)|}} wuv=N(u)N(v) iN(u)N(v)log(1+N(i))1

1.4 MSD

均方差误差也可以作为相似度,只不过此时值越小,越相似
w u v = ∑ i ∈ N ( u ) ∩ N ( v ) ( r u i − r v i ) 2 ∣ N ( u ) ∩ N ( v ) ∣ w_{uv}=\frac{\sum_{i\in N(u)\cap N(v)}(r_{ui}-r_{vi})^2}{|N(u)\cap N(v)|} wuv=N(u)N(v)iN(u)N(v)(ruirvi)2

1.5 Pearson相似度

我们定义 μ u \mu_u μu为用户 u u u的平均打分。

w u v = ∑ i ∈ N ( u ) ∩ N ( v ) ( r u i − μ u ) ( r v i − μ v ) ∑ i ∈ N ( u ) ( r u i − μ u ) 2 ⋅ ∑ i ∈ N ( v ) ( r v i − μ v ) 2 w_{uv}=\frac{\sum_{i\in N(u)\cap N(v)}(r_{ui}-\mu_u)(r_{vi}-\mu_v)}{\sqrt{\sum_{i\in N(u)}(r_{ui}-\mu_u)^2\cdot \sum_{i\in N(v)}(r_{vi}-\mu_v)^2}} wuv=iN(u)(ruiμu)2iN(v)(rviμv)2 iN(u)N(v)(ruiμu)(rviμv)

从表达式可以看出来,pearson相似度其实是中心化之后的consine相似度。

2. itemCF里的相似度

定义 N ( i ) N(i) N(i)为购买过物品 i i i的用户集合。类似的,我们有两个物品之间的Jaccard相似度和余弦相似度。

2.1 Jaccard相似度

物品 i i i和物品 j j j之间的Jaccard相似度为
w i j = ∣ N ( i ) ∩ N ( j ) ∣ ∣ N ( i ) ∪ N ( j ) ∣ w_{ij}=\frac{|N(i)\cap N(j)|}{|N(i)\cup N(j)|} wij=N(i)N(j)N(i)N(j)

意思为,购买两个物品的人里面,同时购买两个物品的比例越高,越能说明两个物品相似。

2.2 余弦相似度

物品 i i i和物品 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)

当然,也能利用用户评分数据,如下
w i j = ∑ u ∈ N ( i ) ∩ N ( j ) r u i ⋅ r u j ∑ u ∈ N ( i ) r u i 2 ⋅ ∑ u ∈ N ( j ) r u j 2 w_{ij}=\frac{\sum_{u\in N(i)\cap N(j)}r_{ui}\cdot r_{uj}}{\sqrt{\sum_{u\in N(i)}r_{ui}^2\cdot\sum_{u\in N(j)}r_{uj}^2}} wij=uN(i)rui2uN(j)ruj2 uN(i)N(j)ruiruj

有了相似度定义,我们就可以进一步定义用户 u u u对物品 i i i的打分 p ( u , i ) p(u, i) p(u,i)

2.3 MSD

均方差误差也可以作为相似度,只不过此时值越小,越相似
w i j = ∑ u ∈ N ( i ) ∩ N ( j ) ( r u i − r u j ) 2 ∣ N ( i ) ∩ N ( j ) ∣ w_{ij}=\frac{\sum_{u\in N(i)\cap N(j)}(r_{ui}-r_{uj})^2}{|N(i)\cap N(j)|} wij=N(i)N(j)uN(i)N(j)(ruiruj)2

2.4 Pearson相似度

我们定义 μ i \mu_i μi为物品 i i i的平均得分。

w i j = ∑ u ∈ N ( i ) ∩ N ( j ) ( r u i − μ i ) ( r u j − μ j ) ∑ u ∈ N ( i ) ( r u i − μ i ) 2 ⋅ ∑ u ∈ N ( j ) ( r u j − μ j ) 2 w_{ij}=\frac{\sum_{u\in N(i)\cap N(j)}(r_{ui}-\mu_i)(r_{uj}-\mu_j)}{\sqrt{\sum_{u\in N(i)}(r_{ui}-\mu_i)^2\cdot \sum_{u\in N(j)}(r_{uj}-\mu_j)^2}} wij=uN(i)(ruiμi)2uN(j)(rujμj)2 uN(i)N(j)(ruiμi)(rujμj)

打分函数 p ( u , i ) p(u, i) p(u,i)

由于userCF和itemCF的打分函数并不一样,所以我们依然分开来说。

1. userCF

这里,用户 u u u对物品 i i i评分,需要

  • 根据用户相似度,找出用户 u u u最相似的其他 k k k个用户,我们将这些用户集合记为 S ( u , k ) S(u, k) S(u,k)
  • 从集合 S ( u , k ) S(u, k) S(u,k)中,找出购买过物品 i i i的用户 v v v,也就是 v ∈ S ( u , k ) ∩ N ( i ) v\in S(u, k)\cap N(i) vS(u,k)N(i)
  • 计算如下打分函数 p ( u , i ) = ∑ v ∈ S ( u , k ) ∩ N ( i ) w u v ⋅ r u i ∑ v ∈ S ( u , k ) ∩ N ( i ) w u v p(u, i)=\frac{\sum_{v\in S(u, k)\cap N(i)} w_{uv}\cdot r_{ui}}{\sum_{v\in S(u, k)\cap N(i)} w_{uv}} p(u,i)=vS(u,k)N(i)wuvvS(u,k)N(i)wuvrui
2. itemCF

这里,用户 u u u对物品 i i i评分,需要

  • 根据物品相似度,计算物品 i i i最相似的 k k k个物品,将这些物品的集合记为 S ( i , k ) S(i, k) S(i,k)
  • 在物品集合 S ( i , k ) S(i, k) S(i,k)中,找到用户 u u u也使用过的物品 j j j,这里, j ∈ S ( i , k ) ∩ N ( u ) j\in S(i, k)\cap N(u) jS(i,k)N(u)
  • 计算如下打分函数 p ( u , i ) = ∑ j ∈ S ( i , k ) ∩ N ( u ) w i j ⋅ r u j ∑ j ∈ S ( i , k ) ∩ N ( u ) w i j p(u, i)=\frac{\sum_{j\in S(i, k)\cap N(u)}w_{ij}\cdot r_{uj}}{\sum_{j\in S(i, k)\cap N(u)}w_{ij}} p(u,i)=jS(i,k)N(u)wijjS(i,k)N(u)wijruj

有了用户 u u u对物品 i i i的评分,我们就可以根据评分,生成对用户 u u u的推荐。

简单实战

下面,我们利用surprise库,对数据集movielens进行电影推荐。

movielens数据集已经上传,可以免费下载。

# 第三方库
import pandas as pd
import numpy as np
from surprise import Dataset, Reader
from surprise import KNNBasic
# 载入数据
data = pd.read_csv(r'D:\myfile\开课吧\推荐系统\第八节\movielens\ratings.csv')
data.head()
# 将timestamp列去掉
data.drop('timestamp', axis=1, inplace=True)
data.head()
# 将数据载入surprise

# 定义阅读器
reader = Reader(line_format='user item rating')
# 载入数据
raw_data = Dataset.load_from_df(data, reader=reader)
# 将数据转化为可操作数据
my_data = raw_data.build_full_trainset()
# userCF
# 领域内有40个用户
# 相似度为余弦相似度
algo = KNNBasic(k=40, sim_options={'user_based': True, 'name': 'cosine'})
algo.fit(my_data)
# userCF
# items,记录所有产品
items = data['movieId'].unique().tolist()

# 字典user_items,记录用户购买过的产品
user_items = {}
for user, group in data.groupby('userId'):
    user_items[user] = set(group['movieId'].tolist())
    
# 给用户u推荐
def topN(u, N=4):
    scores = {}
    
    for i in items:
        if i not in user_items[u]:
            scores[i] = algo.predict(u, i).est
    
    return sorted(scores.items(), key=lambda x: x[1], reverse=True)[: N]  
# userCF 
# 测试
topN(1)
# userCF
# 测试结果
[(60482, 5), (107230, 5), (31123, 5), (134, 5)]
# itemCF
# 训练模型
algo = KNNBasic(k=40, sim_options={'user_based': False, 'name': 'cosine'})
algo.fit(my_data)
# itemCF
# items,记录所有产品
items = data['movieId'].unique().tolist()

# 字典user_items,记录用户购买过的产品
user_items = {}
for user, group in data.groupby('userId'):
    user_items[user] = set(group['movieId'].tolist())
    
# 给用户u推荐
def topN(u, N=4):
    scores = {}
    
    for i in items:
        if i not in user_items[u]:
            scores[i] = algo.predict(u, i).est
    
    return sorted(scores.items(), key=lambda x: x[1], reverse=True)[: N]  
# itemCF
# 测试
topN(1)
# itemCF
# 测试结果
[(93320, 5), (26368, 5), (26520, 5), (26928, 5)]

你可能感兴趣的:(usrcf,itemcf)