0%

基准预测思想在推荐里的应用

介绍基准预测思想在推荐里的应用

背景

接上文,KNN在推荐领域的应用文章里介绍了KNN在推荐系统里如何预测评分。但是,在实际用户评论时,每个用户都有自己的评分体系,有的用户要求相对苛刻,五分制的评分里一般只给到一二分,有的用户相对“心慈手软”一般会给到四五分。同时,对于电影来说,有的电影本身自带光环,随上映时间等因素也会有偏差。如何减少上述问题给预测带来的负面影响,本文将着重阐述。

解决思路

无论是个体用户还是物品,评分普遍高于或低于平均值的差值,我们称为偏置(bias)。

所有电影的平均评分$\mu$(即全局平均评分)

每个用户评分与平均评分$\mu$的偏置值$b_u$

每部电影所接受的评分与平均评分$\mu$的偏置值$b_i$

那么,预测用户对电影的评分则是:

举例[1]

​ 比如我们想通过Baseline来预测用户A对电影“阿甘正传”的评分,那么首先计算出整个评分数据集的平均评分$\mu$是3.5分;而用户A是一个比较苛刻的用户,他的评分比较严格,普遍比平均评分低0.5分,即用户A的偏置值$b_i$是-0.5;而电影“阿甘正传”是一部比较热门而且备受好评的电影,它的评分普遍比平均评分要高1.2分,那么电影“阿甘正传”的偏置值$b_i$是+1.2,因此就可以预测出用户A对电影“阿甘正传”的评分为:$3.5+(-0.5)+1.2$,也就是4.2分。

由此而来,我们把预测某个用户对某个电影的评分,转变成求偏置参数$b_u$和$b_i$的最优解的线性回归问题。

代价函数是:

最优化问题是应用数学的重要研究领域,主要研究在给定约束的情况下如何寻求某个因素,使某一指标达到最优。

梯度下降解法

如果将代价函数是 $y=k(x+b)^2$,求当y的最小值时,x应该为多少。这个问题很简单,属于高中数学。但是问题在复杂一些,变成$y=k(x+z+b)^2$,x和z 与将会组成一个三维图形。如何找到最低点,可以采用一个逐步逼近的策略,即梯度下降。具体可以参见深入浅出—梯度下降法及其实现

image-20190830012131423

推导过程

损失函数:

梯度下降参数更新原始公式:

损失函数偏导推导:

bu更新(因为alpha可以人为控制,所以2可以省略掉):

同理可得,梯度下降更新$b_i$:

代码说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import pandas as pd
import numpy as np

# 1. 数据加载
dtype = [("userId", np.int32), ("movieId", np.int32), ("rating", np.float32)]
dataset = pd.read_csv("./data/ml-latest-small/ratings.csv", usecols=range(3), dtype=dict(dtype))
print(dataset.head())
users_ratings = dataset.groupby("userId").agg([list])
print(users_ratings.head())
items_ratings = dataset.groupby("movieId").agg([list])
print(items_ratings.head())

# 计算全局的平均分
global_mean = dataset['rating'].mean()

# 初始化bu bi
bu = dict(zip(users_ratings.index, np.zeros(len(users_ratings.index))))
bi = dict(zip(items_ratings.index, np.zeros(len(items_ratings.index))))

for i in range(10):
print('iter%d' % i)
for uid, iid, real_rating in dataset.itertuples(index=False):
# 计算损失
error = real_rating - (global_mean + bu[uid] + bi[iid])
bu[uid] += 0.1 * (error - 0.1 * bu[uid])
bi[iid] += 0.1 * (error - 0.1 * bi[iid])

print(bu)
print(bi)

# 预测评分
def predit(uid, iid):
predit_rating = global_mean + bu[uid] + bi[iid]
return predit_rating

print(predit(1,1))
觉得不错?