Обзор
Ранее для вычисления подобия использовались пользовательский вектор и вектор элементов, но если это разреженный массив, в номере группы имеется большое количество значений None, что может привести к некоторым сходствам, которые невозможно вычислить. Обычно это не используется в производственных средах.
Baseline
Это совместная фильтрация, основанная на регрессионной модели. Если мы будем рассматривать рейтинг как непрерывное значение, а не как дискретное значение, то мы можем использовать идею линейной регрессии, чтобы предсказать рейтинг целевого пользователя для элемента. Одна из стратегий реализации называется Baseline.
Базовое дизайн-мышление
-
Некоторые пользователи обычно оцениваются выше, чем другие, а некоторые пользователи обычно оцениваются ниже, чем другие. Например, некоторые пользователи от природы склонны хвалить других, они мягкосердечны и легки в общении, а некоторые более суровы и всегда ставят не более 3 баллов (из 5 баллов).
-
Некоторые элементы обычно оцениваются выше, чем другие, а некоторые, как правило, оцениваются ниже, чем другие. Например, некоторые предметы определяют свой статус сразу после их производства, некоторые пользуются большей популярностью у людей, а другие не нравятся.
Этот пользователь или элемент, как правило, выше или ниже средней разницы, мы называем смещение (bias)
Базовая цель
-
Найдите значение смещения b, согласно которому каждый пользователь обычно выше или ниже других.u
-
Найдите значение смещения b каждого элемента, как правило, выше или ниже, чем у других элементов.i
-
Наша цель – найти оптимальное buи бi
Чтобы предотвратить переоснащение, регуляризация
градиентный спуск
уже b в приведенной выше формулеuс бiбинарная функция
Введите формулу градиента
В приведенной выше формуле необходимо рассчитать сумму рейтинга каждого пользователя по элементу и прогнозируемого рейтинга, который можно использоватьСтохастический градиентный спуск
так какСтохастический градиентный спускПо существу использоватьпотери на образецобновлять параметры, не находя каждый раз полную сумму убытка
Реализация алгоритма
# 数据文件可以到这里下载 https://grouplens.org/datasets/movielens/
import pandas as pd
import numpy as np
from scipy.interpolate import make_interp_spline
class BaselineCFBySGD(object):
def __init__(self, number_epochs, alpha, reg, columns=["uid", "iid", "rating"]):
# 梯度下降最高迭代次数
self.number_epochs = number_epochs
# 学习率或者跨步
self.alpha = alpha
# 正则参数
self.reg = reg
# 数据集中user-item-rating字段的名称
self.columns = columns
def fit(self, dataset):
'''
:param dataset: uid, iid, rating
:return:
'''
self.dataset = dataset
# 用户评分数据
print(self.dataset.itertuples(index=False))
self.users_ratings = dataset.groupby(self.columns[0]).agg([list])[[self.columns[1], self.columns[2]]]
# 物品评分数据
self.items_ratings = dataset.groupby(self.columns[1]).agg([list])[[self.columns[0], self.columns[2]]]
# 计算全局平均分
self.global_mean = self.dataset[self.columns[2]].mean()
# 调用sgd方法训练模型参数
self.bu, self.bi = self.sgd()
self.showChart()
def sgd(self):
'''
利用随机梯度下降,优化bu,bi的值
:return: bu, bi
'''
# 初始化bu、bi的值,全部设为0
bu = dict(zip(self.users_ratings.index, np.zeros(len(self.users_ratings))))
bi = dict(zip(self.items_ratings.index, np.zeros(len(self.items_ratings))))
for i in range(self.number_epochs):
print("iter %d" % i)
for uid, iid, real_rating in self.dataset.itertuples(index=False):
error = real_rating - (self.global_mean + bu[uid] + bi[iid])
bu[uid] += self.alpha * (error - self.reg * bu[uid])
bi[iid] += self.alpha * (error - self.reg * bi[iid])
return bu, bi
def predict(self, uid, iid):
'''预测'''
predict_rating = self.global_mean + self.bu[uid] + self.bi[iid]
return predict_rating
def showChart(self):
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
plt.title("匹配结果")
userId = self.users_ratings.index.values[10]
# 查看指定用户的预测曲线
# 找到该用户评分的电影
movie_ids = []
real_ratings = []
for uid, iid, real_rating in self.dataset.itertuples(index=False):
if uid == userId:
movie_ids.append(iid)
real_ratings.append(real_rating)
model = make_interp_spline(movie_ids, real_ratings)
xs = np.linspace(min(movie_ids), max(movie_ids), 1000)
ys = model(xs)
plt.plot(xs, ys, color='green', label='training accuracy')
predict_ratings = []
for iid in movie_ids:
predict_ratings.append(self.predict(userId, iid))
model = make_interp_spline(movie_ids, predict_ratings)
xs = np.linspace(min(movie_ids), max(movie_ids), 1000)
ys = model(xs)
plt.plot(xs, ys, color='red', label='training accuracy')
plt.xticks([])
plt.yticks([])
plt.show()
if __name__ == '__main__':
dtype = [("userId", np.int32), ("movieId", np.int32), ("rating", np.float32)]
dataset = pd.read_csv("datasets/ml-latest-small/ratings.csv", usecols=range(3), dtype=dict(dtype))
bcf = BaselineCFBySGD(10, 0.1, 0.1, ["userId", "movieId", "rating"])
bcf.fit(dataset)
# while True:
# uid = int(input("uid: "))
# iid = int(input("iid: "))
# print(bcf.predict(uid, iid))