# 【推荐系统入门到项目实践】(四):Baseline和Slope one算法

简介: # 【推荐系统入门到项目实践】(四):Baseline和Slope one算法

【推荐系统入门到项目实践】(四):Baseline和Slope one算法


  • 🌸个人主页:JOJO数据科学
  • 📝个人介绍:统计学top3高校统计学硕士在读
  • 💌如果文章对你有帮助,欢迎✌关注、👍点赞、✌收藏、👍订阅专栏
  • ✨本文收录于【推荐系统入门到项目实战】本系列主要分享一些学习推荐系统领域的方法和代码实现。

@[TOC]

引言

在上一篇文章中我们介绍了矩阵分解和ALS算法,上面这种方法的一个缺点是只使用了个性化推荐部分,没有考虑到物品和用户本身的整体情况。因此,下面介绍介绍两种用于反映一个整体情况推荐的方法。

baseline算法

基本原理

Baseline算法:基于统计的基准预测线打分

$b_{ui}$ 预测值

$b_u$ 用户对整体的偏差

$b_i$ 商品对整体的偏差

$$ b_{ui}=u+b_{u}+b_i $$

以对泰坦尼克号评分为例,其中$b_{ui}$指的是 预测值,$u$指的是所有电影的 平均得分,$b_{u}$表示的是 泰坦尼克号比其他电影平均多的评分(如果是负数则少的评分),$b_i$指的是 用户的评分误差,假设他比较苛刻,可能比其他用户平均少打的分数

使用ALS来估计Baseline算法

Step1,固定bu,优化bi

Step2,固定bi,优化bu

image-20220803113938941

实现方法

我们使用Surprise库来实现(https://surprise.readthedocs.io/en/stable/

surprise包含了许多推荐算法的实现方法。常用的几种方法如下:

算法 描述
NormalPredictor() 基于统计的推荐系统预测打分,假定用户打分的分布是基于正态分布的
BaselineOnly 基于统计的基准预测线打分
knns.KNNBasic 基本的协同过滤算法
knns.KNNWithMeans 协同过滤算法的变种,考虑每个用户的平均评分
knns.KNNWithZScore 协同过滤算法的变种,考虑每个用户评分的归一化操作
knns.KNNBaseline 协同过滤算法的变种,考虑每个用户评分的基线
matrix_factorzation.SVD SVD 矩阵分解算法
matrix_factorzation.SVDpp SVD++ 矩阵分解算法
matrix_factorzation.NMF 一种非负矩阵分解的协同过滤算法
SlopeOne SlopeOne 协同过滤算法

其中baseline算法包含两个主要的方法NormalPredictorBaselineOnly

Normal Perdictor 认为用户对物品的评分是服从正态分布的,从而可以根据已有的评分的均值和方差预测当前用户对其他物品评分的分数。

BaselineOnly算法的思想就是设立基线,并引入用户的偏差以及item的偏差

image-20221022143247534

μ为所有用户对电影评分的均值

$b_{ui}$:待求的基线模型中用户u给物品i打分的预估值

$b_u$:user偏差(如果用户比较苛刻,打分都相对偏低, 则bu<0;反之,bu>0);

$b_i$:item偏差,反映商品受欢迎程度

评估方法

K折交叉验证

将训练集数据划分为K份,使用其中的K-1份作为训练集,剩余一份作为测试集

K次误差的平均值作为泛化误差

所有数据都做过训练和测试,更好的利用数据

K越大,平均误差作为泛化误差的结果就越可靠,但花费的时间也时间也越长

image-20221022143444226

Surprise中的评价指标

RMSE:均方根误差

image-20221022144133214

MAE:平均绝对误差

image-20221022144138464

下面我们以RMSE为评估指标,使用baselines算法对评分数据集进行预测。

代码实现

from surprise import Dataset
from surprise import Reader
from surprise import BaselineOnly, KNNBasic, NormalPredictor
from surprise import accuracy
from surprise.model_selection import KFold
#import pandas as pd

# 数据读取
reader = Reader(line_format='user item rating timestamp', sep=',', skip_lines=1)
data = Dataset.load_from_file('MovieLens/ratings.csv', reader=reader)
train_set = data.build_full_trainset()

# ALS优化
bsl_options = {'method': 'als','n_epochs': 5,'reg_u': 12,'reg_i': 5}
# SGD优化
#bsl_options = {'method': 'sgd','n_epochs': 5}
algo = BaselineOnly(bsl_options=bsl_options)
#algo = BaselineOnly()
#algo = NormalPredictor()#大家也可以试一下这个方法

# 定义K折交叉验证迭代器,K=3
kf = KFold(n_splits=3)
for trainset, testset in kf.split(data):
    # 训练并预测
    algo.fit(trainset)
    predictions = algo.test(testset)
    # 计算RMSE
    accuracy.rmse(predictions, verbose=True)

uid = str(196)
iid = str(302)
# 输出uid对iid的预测结果
pred = algo.predict(uid, iid, r_ui=4, verbose=True)



Estimating biases using als...
RMSE: 0.8635
Estimating biases using als...
RMSE: 0.8644
Estimating biases using als...
RMSE: 0.8636
user: 196        item: 302        r_ui = 4.00   est = 4.07   {'was_impossible': False}

est为我们的预测值,$r_{ui}$为真实值。可以看出预测的结果还不错,但是其实这种方法没有利用到用户和物品之间的交互信息,更多的是从一个某个用户或者某个商品的总体情况来进行预测,当数据质量较好时,这种方法的效果还不错。下面我们再来介绍一种更简单的方法。

SlopeOne算法

基本原理

Slope One 是一系列应用于协同过滤的算法的统称。由 Daniel LemireAnna Maclachlan于2005年发表的论文中提出。有争议的是,该算法堪称基于项目评价的协同过滤算法最简洁的形式。该系列算法的简洁特性使它们的实现简单而高效,而且其精确度与其它复杂费时的算法相比也不相上下。 该系列算法也被用来改进其它算法。它最大优点在于算法很简单, 易于实现, 效率高且推荐准确度较高

为什么说他简单呢?因为在本质上,它其实是运用了一个回归表达式$f(x)=x+b$,其中只有一个单一的自由参数b。我想这也是它的名字来源吧,slope我们知道是斜率的意思,slope one也就是斜率为1。该自由参数只不过就是两个项目评分间的平均差值。甚至在某些实例当中,它比线性回归的方法更准确,而且该算法只需要一半(甚至更少)的存储量。

下面我们来看看具体是怎么计算的。

用户 商品1评分 商品2
A 5 3
B 4 3
C 4 ?

我们现在有三个用户对两个商品的评分矩阵,如上表所示,但是c对商品2的评分我们是未知的,那么我们怎么估计它呢?

我们根据A,B用户对两个商品的评分差值来进行估计。

用户A:商品1-商品2=(5-3)=2

用户B:商品1-商品2=4-3=1

那么我们认为商品1平均比商品2评分要高(1+2)/2=1.5。那么我们就可以计算出用户C对商品2的评分

C对商品2的评分=4-((5-3)+(4-3))/2=2.5

那么我们现在来看看slopeOne算法的一般步骤

Step1,计算Item之间的评分差的均值,记为评分偏差(两个item都评分过的用户)

image-20221022151649334

Step2,根据Item间的评分偏差和用户的历史评分,预测用户对未评分的item的评分

Step3,将预测评分排序,取topN对应的item推荐给用户

下面我们来看一个更复杂的具体的案例:

a b c d
A 5 3.5
B 2 5 4 2
C 4.5 3.5 1 4

我们要补全上面这个评分矩阵

Step1,计算Item之间的评分差的均值

b与a:((3.5-5)+(5-2)+(3.5-4.5))/3=0.5/3

c与a:((4-2)+(1-4.5))/2=-1.5/2

d与a:((2-2)+(4-4.5))/2=-0.5/2

c与b:((4-5)+(1-3.5))/2=-3.5/2

d与b:((2-5)+(4-3.5))/2=-2.5/2

d与c:((2-4)+(4-1))/2=1/2

将上面计算结果写成矩阵的形式,如下所示,我们称为评分偏差矩阵,以0.17为例,表示商品b比a平均高0.17分

a b c d
a
b 0.17
c -0.75 -1.75
d -0.25 -1.25 0.5

Step2,预测用户A对商品c和d的评分

A对c评分=((-0.75+5)+(-1.75+3.5))/2=3

A对d评分=((-0.25+5)+(-1.25+3.5))/2=3.5

a b c d
A 5 3.5 3 3.5
B 2 5 4 2
C 4.5 3.5 1 4

Step3,将预测评分排序,推荐给用户

推荐顺序为{d, c}

加权算法 Weighted Slope One

如果有100个用户对Item1和Item2都打过分, 有1000个用户对Item3和Item2也打过分,显然这两个rating差的权重是不一样的,因此计算方法为:

(100*(Rating 1 to 2) + 1000(Rating 3 to 2)) / (100 + 1000)

SlopeOne算法的特点

适用于item更新不频繁,数量相对较稳定

item数<<user数

算法简单,易于实现,执行效率高

依赖用户行为,存在冷启动问题和稀疏性问题

用户 商品1评分 商品2
X 5 3
Y 4 3
Z 4 ?

代码实现

from surprise import SVD
from surprise import Dataset
from surprise.model_selection import cross_validate
#from surprise import evaluate, print_perf
from surprise import Reader
from surprise import BaselineOnly, KNNBasic, KNNBaseline, SlopeOne
from surprise import accuracy
from surprise.model_selection import KFold
import pandas as pd
import io
import pandas as pd

# 读取物品(电影)名称信息
def read_item_names():
    file_name = ('./movies.csv') 
    data = pd.read_csv('./movies.csv')
    rid_to_name = {}
    name_to_rid = {}
    for i in range(len(data['movieId'])):
        rid_to_name[data['movieId'][i]] = data['title'][i]
        name_to_rid[data['title'][i]] = data['movieId'][i]

    return rid_to_name, name_to_rid 

# 数据读取
reader = Reader(line_format='user item rating timestamp', sep=',', skip_lines=1)
data = Dataset.load_from_file('MovieLens/ratings.csv', reader=reader)
train_set = data.build_full_trainset()


# 使用SlopeOne算法
algo = SlopeOne()
algo.fit(train_set)
# 对指定用户和商品进行评分预测
uid = str(196) 
iid = str(302) 
pred = algo.predict(uid, iid, r_ui=4, verbose=True)
user: 196        item: 302        r_ui = 4.00   est = 4.32   {'was_impossible': False}

可以看出,使用slopeone算法得到的预测结果为4.32,效果似乎相对于baseline算法要差一些,其实这也不难猜到,因为我们毕竟用的是一个太简单的模型。但是他对于数据量相对没那么敏感

总结

介绍了baseline算法slopeOne算法。

baseline算法的核心思想是将用户评分分解成三个部分

  • $u$:平均评分
  • $b_u$:用户评分偏差
  • $b_i$:物品评分偏差

然后使用ALS方法进行求解

SlopeOne算法的核心思想根据用户对不同商品评分的差异来预测某一商品的评分。大家记得那个具体的案例即可。

下一章我们将讨论SVD矩阵分解以及一些拓展的模型。

相关文章
|
5天前
|
算法 搜索推荐 Java
【潜意识Java】深度解析黑马项目《苍穹外卖》与蓝桥杯算法的结合问题
本文探讨了如何将算法学习与实际项目相结合,以提升编程竞赛中的解题能力。通过《苍穹外卖》项目,介绍了订单配送路径规划(基于动态规划解决旅行商问题)和商品推荐系统(基于贪心算法)。这些实例不仅展示了算法在实际业务中的应用,还帮助读者更好地准备蓝桥杯等编程竞赛。结合具体代码实现和解析,文章详细说明了如何运用算法优化项目功能,提高解决问题的能力。
40 6
|
14天前
|
搜索推荐 NoSQL Java
微服务架构设计与实践:用Spring Cloud实现抖音的推荐系统
本文基于Spring Cloud实现了一个简化的抖音推荐系统,涵盖用户行为管理、视频资源管理、个性化推荐和实时数据处理四大核心功能。通过Eureka进行服务注册与发现,使用Feign实现服务间调用,并借助Redis缓存用户画像,Kafka传递用户行为数据。文章详细介绍了项目搭建、服务创建及配置过程,包括用户服务、视频服务、推荐服务和数据处理服务的开发步骤。最后,通过业务测试验证了系统的功能,并引入Resilience4j实现服务降级,确保系统在部分服务故障时仍能正常运行。此示例旨在帮助读者理解微服务架构的设计思路与实践方法。
65 16
|
2月前
|
机器学习/深度学习 算法 Python
机器学习入门:理解并实现K-近邻算法
机器学习入门:理解并实现K-近邻算法
46 0
|
3月前
|
机器学习/深度学习 算法 搜索推荐
django调用矩阵分解推荐算法模型做推荐系统
django调用矩阵分解推荐算法模型做推荐系统
56 4
|
3月前
|
机器学习/深度学习 人工智能 算法
【玉米病害识别】Python+卷积神经网络算法+人工智能+深度学习+计算机课设项目+TensorFlow+模型训练
玉米病害识别系统,本系统使用Python作为主要开发语言,通过收集了8种常见的玉米叶部病害图片数据集('矮花叶病', '健康', '灰斑病一般', '灰斑病严重', '锈病一般', '锈病严重', '叶斑病一般', '叶斑病严重'),然后基于TensorFlow搭建卷积神经网络算法模型,通过对数据集进行多轮迭代训练,最后得到一个识别精度较高的模型文件。再使用Django搭建Web网页操作平台,实现用户上传一张玉米病害图片识别其名称。
94 0
【玉米病害识别】Python+卷积神经网络算法+人工智能+深度学习+计算机课设项目+TensorFlow+模型训练
|
3月前
|
数据采集 搜索推荐
推荐系统实践之新闻推荐baseline理解
推荐系统实践之新闻推荐baseline理解
59 1
|
3月前
|
数据采集 搜索推荐
推荐系统实践之新闻推荐baseline理解
推荐系统实践之新闻推荐baseline理解
104 1
|
3月前
|
机器学习/深度学习 算法 大数据
机器学习入门:梯度下降算法(下)
机器学习入门:梯度下降算法(下)
|
3月前
|
机器学习/深度学习 算法
机器学习入门:梯度下降算法(上)
机器学习入门:梯度下降算法(上)
|
8天前
|
算法 数据安全/隐私保护 计算机视觉
基于Retinex算法的图像去雾matlab仿真
本项目展示了基于Retinex算法的图像去雾技术。完整程序运行效果无水印,使用Matlab2022a开发。核心代码包含详细中文注释和操作步骤视频。Retinex理论由Edwin Land提出,旨在分离图像的光照和反射分量,增强图像对比度、颜色和细节,尤其在雾天条件下表现优异,有效解决图像去雾问题。