任务6 Slope one 推荐算法简单实现
1. 算法原理
算法原理见这篇博客, 这篇博客写的还不错. 我只是实现了最基本的版本
Slope One算法基本原理
2. 代码实现
导入相关的包
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import torch
from tqdm import tqdm
下面这几个包是我自己手动实现的, 在之前的博客里面有具体的代码
import Metirc
from utils import loadData, rating2matrix, Split_Dataset_P
import Similarity
下面这个函数是用来计算矩阵评分差的函数的, 具体计算公式可以看最上面提到的那个博客
def calcu_delta(ratings):
ratingsT = ratings.T
items = ratings.shape[1]
delta = torch.zeros(size=(items, items))
mask = ratingsT > 1e-6
num_rating = mask.float()
num_rating = (num_rating).mm(num_rating.T)
# mask = mask.T
with tqdm(total=(1+ items) * items / 2) as tq:
for i in range(ratingsT.shape[1]):
for j in range(i, ratingsT.shape[1]):
# print((ratingsT[i] - ratingsT[j]).shape)
# print((mask[i] * mask[j]).shape)
t1 = (ratingsT[i] - ratingsT[j]) * (mask[i] * mask[j])
if num_rating[i, j] < 1e-6:
delta[i, j] = 0
else:
delta[i, j] = t1.sum() / num_rating[i, j]
delta[j, i] = -delta[i, j]
tq.update(1)
return delta
这个是利用矩阵的评分差, 来对用户打分进行预测. 这里我们只是对用户没有打过分的物品进行预测
def pred_score2(ratings, delta):
mask = (ratings > 1e-6).float()
nums = mask.sum(dim=1)
index = torch.nonzero(ratings < 1e-6).numpy()
result = torch.zeros_like(ratings, dtype=torch.float32)
with tqdm(total=len(index)) as tq:
for i in index:
num = nums[i[0]].item()
if num < 1e-6:
result[i[0], i[1]] = 0
else:
temp1 = ratings[i[0]] + delta[i[1]]
temp1 = temp1 * mask[i[0]]
# print(temp1)
result[i[0], i[1]] = temp1.sum() / num
tq.update(1)
return result
下面开始读取数据了
ratings = loadData('./', 'ml-100k')
开始读取数据
用户人数为: 943
电影数目为: 1682
把数据划分为训练集和测试集(8:2)划分的
train_data, test_data = Split_Dataset_P(ratings)
开始划分数据集
100%|██████████| 943/943 [00:05<00:00, 177.22it/s]
为了方便计算, 把打分的数据转换成一个矩阵, 方便后面的计算
train_data = rating2matrix(train_data)
test_data = rating2matrix(test_data)
train_data = torch.tensor(train_data)
开始将数据转换成矩阵
用户人数为: 943
电影数目为: 1682
100%|██████████| 79619/79619 [00:06<00:00, 12027.42it/s]
开始将数据转换成矩阵
用户人数为: 943
电影数目为: 1680
100%|██████████| 20381/20381 [00:01<00:00, 13160.30it/s]
我们对训练集来计算一下物品之间的打分差
delta = calcu_delta(train_data)
31%|███▏ | 445096/1415403.0 [01:01<02:14, 7203.28it/s]
利用上面我们得到的打分差矩阵, 利用(下面的公式来自于这篇博客一开始提到的那篇博客)
(
u
j
)
=
∑
i
∈
S
(
u
B
)
(
d
e
v
i
j
+
u
i
)
c
a
r
d
‾
(
S
(
u
B
)
)
(u_j)= \frac {\sum_{i\in S(u_B)}(dev_{ij}+u_i)}{car\underline{d}(S(u_B))}
(uj)=card(S(uB))∑i∈S(uB)(devij+ui)
result = pred_score2(train_data, delta)
100%|██████████| 1506507/1506507 [01:37<00:00, 15514.23it/s]
有了打分矩阵我们就可以开始推荐了(下面这个函数在任务4里面有)
def recommend(score, k = 3):
"""通过预测的物品打分,给用户推荐前k个物品
Args:
score (tensor): 这个是预测的打分
k (int, optional): 推荐前k个物品. Defaults to 3.
Returns:
pred, index: pred是推荐的物品对应的打分,index是推荐的物品的索引
"""
pred, index = torch.topk(input=score, k=k, dim=1)
return pred, index
rec_value, rec_index = recommend(result, k=10)