# 【推荐系统入门到项目实践】(四):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矩阵分解以及一些拓展的模型。

相关文章
|
1月前
|
机器学习/深度学习 算法 搜索推荐
从理论到实践,Python算法复杂度分析一站式教程,助你轻松驾驭大数据挑战!
【10月更文挑战第4天】在大数据时代,算法效率至关重要。本文从理论入手,介绍时间复杂度和空间复杂度两个核心概念,并通过冒泡排序和快速排序的Python实现详细分析其复杂度。冒泡排序的时间复杂度为O(n^2),空间复杂度为O(1);快速排序平均时间复杂度为O(n log n),空间复杂度为O(log n)。文章还介绍了算法选择、分而治之及空间换时间等优化策略,帮助你在大数据挑战中游刃有余。
60 4
|
1月前
|
机器学习/深度学习 人工智能 算法
【玉米病害识别】Python+卷积神经网络算法+人工智能+深度学习+计算机课设项目+TensorFlow+模型训练
玉米病害识别系统,本系统使用Python作为主要开发语言,通过收集了8种常见的玉米叶部病害图片数据集('矮花叶病', '健康', '灰斑病一般', '灰斑病严重', '锈病一般', '锈病严重', '叶斑病一般', '叶斑病严重'),然后基于TensorFlow搭建卷积神经网络算法模型,通过对数据集进行多轮迭代训练,最后得到一个识别精度较高的模型文件。再使用Django搭建Web网页操作平台,实现用户上传一张玉米病害图片识别其名称。
58 0
【玉米病害识别】Python+卷积神经网络算法+人工智能+深度学习+计算机课设项目+TensorFlow+模型训练
|
1月前
|
数据采集 搜索推荐
推荐系统实践之新闻推荐baseline理解
推荐系统实践之新闻推荐baseline理解
29 1
|
1月前
|
机器学习/深度学习 算法 Python
探索机器学习中的决策树算法:从理论到实践
【10月更文挑战第5天】本文旨在通过浅显易懂的语言,带领读者了解并实现一个基础的决策树模型。我们将从决策树的基本概念出发,逐步深入其构建过程,包括特征选择、树的生成与剪枝等关键技术点,并以一个简单的例子演示如何用Python代码实现一个决策树分类器。文章不仅注重理论阐述,更侧重于实际操作,以期帮助初学者快速入门并在真实数据上应用这一算法。
|
1月前
|
数据采集 搜索推荐
推荐系统实践之新闻推荐baseline理解
推荐系统实践之新闻推荐baseline理解
52 1
|
1月前
|
机器学习/深度学习 人工智能 Rust
MindSpore QuickStart——LSTM算法实践学习
MindSpore QuickStart——LSTM算法实践学习
40 2
|
1月前
|
机器学习/深度学习 算法 大数据
机器学习入门:梯度下降算法(下)
机器学习入门:梯度下降算法(下)
|
1月前
|
机器学习/深度学习 算法 API
机器学习入门(五):KNN概述 | K 近邻算法 API,K值选择问题
机器学习入门(五):KNN概述 | K 近邻算法 API,K值选择问题
|
1月前
|
机器学习/深度学习 算法 数据建模
计算机前沿技术-人工智能算法-生成对抗网络-算法原理及应用实践
计算机前沿技术-人工智能算法-生成对抗网络-算法原理及应用实践
30 0