Movie推荐系统

MovieLens推荐系统
转载此
基于内存的协同过滤
可以分为两个主要部分:用户-产品协同过滤产品-产品协同过滤
在这两种情况下,从整个数据集构建一个用户-产品矩阵。由于你已经将数据拆分到测试集和训练集,那么你将需要创建两个[943 x 1682]矩阵。训练矩阵包含75%的打分,而测试矩阵包含25%的打分。

思路
1.1 在构建了用户-产品矩阵后,计算相似性并创建一个相似性矩阵。
1.2. 对于用户-产品协同过滤,用户之间的相似性值是通过观察所有同时被两个用户打分的产品来度量的。

2.在产品-产品协同过滤中的产品之间的相似性值是通过观察所有对两个产品之间的打分的用户来度量的。

通常用于推荐系统中的距离矩阵是余弦相似性,其中,打分被看成n维空间中的向量,而相似性是基于这些向量之间的角度进行计算的。

问题
1、某些用户可能会倾向于对所有的电影,总是给予高或低评分。这些用户提供的评分的相对差比绝对评分值更重要。举个例子:假设,用户k对他最喜欢的电影打4星,而对所有其他的好电影打3星。现在假设另一个用户t对他/她喜欢的电影打5星,而对他/她感到无聊的电影打3星。那么这两个用户可能品味非常相似,但对打分系统区别对待。
2、基于内存的CF的缺点是,它不能扩展到真实世界的场景,并且没有解决众所周知的冷启动问题,也就是当新用户或新产品进入系统时。基于模型的CF方法是可扩展的,并且可以比基于内存的模型处理更高的稀疏度,但当没有任何评分的用户或产品进入系统时,也是苦不堪言的。

基于内存的协同过滤完整代码

import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.metrics.pairwise import pairwise_distances
from sklearn.metrics import mean_squared_error
from math import sqrt

#一、基于内存的协同过滤
#1、导入数据,数据分割
header = ['user_id', 'item_id', 'rating', 'timestamp']
df = pd.read_csv('ml-100k/u.data', sep='\t', names=header)
n_users = df.user_id.unique().shape[0]
n_items = df.item_id.unique().shape[0]
print('Number of users = ' + str(n_users) + ' | Number of movies = ' + str(n_items))
train_data, test_data = train_test_split(df, test_size=0.25)

#创建用户-产品矩阵。由于你既有测试数据,又有训练数据,那么你需要创建两个矩阵。
train_data_matrix = np.zeros((n_users, n_items))
for line in train_data.itertuples():
    train_data_matrix[line[1] - 1, line[2] - 1] = line[3]

test_data_matrix = np.zeros((n_users, n_items))
for line in test_data.itertuples():
    test_data_matrix[line[1] - 1, line[2] - 1] = line[3]

#计算余弦相似性 输出范围0-1
user_similarity = pairwise_distances(train_data_matrix, metric='cosine')
item_similarity = pairwise_distances(train_data_matrix.T, metric='cosine')
print(user_similarity)
print(item_similarity)

#基于产品的CF进行预测
def predict(ratings, similarity, type='user'):
    if type == 'user':
        mean_user_rating = ratings.mean(axis=1)
        # You use np.newaxis so that mean_user_rating has same format as ratings
        ratings_diff = (ratings - mean_user_rating[:, np.newaxis])
        pred = mean_user_rating[:, np.newaxis] + similarity.dot(ratings_diff) / np.array(
            [np.abs(similarity).sum(axis=1)]).T
    elif type == 'item':
        pred = ratings.dot(similarity) / np.array([np.abs(similarity).sum(axis=1)])
    return pred

item_prediction = predict(train_data_matrix, item_similarity, type='item')
user_prediction = predict(train_data_matrix, user_similarity, type='user')
print(item_prediction)
print(user_prediction)


#计算均方根误差
def rmse(prediction, ground_truth):
    prediction = prediction[ground_truth.nonzero()].flatten()
    ground_truth = ground_truth[ground_truth.nonzero()].flatten()
    return sqrt(mean_squared_error(prediction, ground_truth))

print('User-based CF RMSE: ' + str(rmse(user_prediction, test_data_matrix)))
print('Item-based CF RMSE: ' + str(rmse(item_prediction, test_data_matrix)))

基于模型的协同过滤
优势
基于模型的协同过滤是基于矩阵分解(MF),它已获得更大的曝光,它主要是作为潜变量分解和降维的一个无监督学习方法。矩阵分解广泛用于推荐系统,其中,它比基于内存的CF可以更好地处理与扩展性和稀疏性. MF的目标是从已知的评分中学习用户的潜在喜好和产品的潜在属性(学习描述评分特征的特征),随后通过用户和产品的潜在特征的点积预测未知的评分。
作法
当你有一个非常稀疏的多维矩阵时,通过进行矩阵分解可以调整用户-产品矩阵为低等级的结构,然后你可以通过两个低秩矩阵(其中,每行包含该本征矢量)的乘积来代表该矩阵。你通过将低秩矩阵相乘,在原始矩阵填补缺少项,以调整这个矩阵,从而尽可能的近似原始矩阵。

举例说明:用户和产品的学习隐藏偏好
假设MovieLens数据集中有以下信息:(user id, age, location, gender, movie id, director, actor, language, year, rating)。通过应用矩阵分解,模型学习到重要的用户特征是年龄组(10岁以下,10-18岁,18-30岁,30-90岁),位置和性别,而对于电影特性,它学习到年份,导演和演员是最重要的。现在,如果你看看你所存储的信息,其中并没有年份这样的特性,但该模型可以自己学习。重要方面是,CF模型仅使用数据(user_id, movie_id, rating)来学习潜在特征。如果只有少数可用的数据,那么基于模型的CF模式将预测不良,因为这将更难以学习潜在特征。

同时使用评分和内容特性的模型称为混合推荐系统,其中,协同过滤和基于内容的模型相结合。混合推荐系统通常比协同过滤或基于内容的模型自身表现出更高的精度:它们有能力更好的解决冷启动问题,因为如果你没有一个用户或者一个产品的评分,那么你可以使用该用户或产品的元数据进行预测
SVD
一个众所周知的矩阵分解方法是奇异值分解(SVD)。通过使用奇异值分解,协同过滤可以被近似一个矩阵X所制定

# 让我们计算MovieLens数据集的稀疏度:
sparsity = round(1.0 - len(df) / float(n_users * n_items), 3)
print('The sparsity level of MovieLens100K is ' + str(sparsity * 100) + '%')

# 奇异值分解(SVD)
import scipy.sparse as sp
from scipy.sparse.linalg import svds

# get SVD components from train matrix. Choose k.
u, s, vt = svds(train_data_matrix, k=20)
s_diag_matrix = np.diag(s)
X_pred = np.dot(np.dot(u, s_diag_matrix), vt)

print('User-based CF MSE: ' + str(rmse(X_pred, test_data_matrix)))

控制台

Number of users = 943 | Number of movies = 1682
[[0.         0.89836005 0.97986307 ... 0.85458633 0.87920808 0.67340185]
 [0.89836005 0.         0.91582156 ... 0.91960457 0.87277272 0.91170124]
 [0.97986307 0.91582156 0.         ... 0.97600463 0.91078074 1.        ]
 ...
 [0.85458633 0.91960457 0.97600463 ... 0.         0.97246425 0.94329862]
 [0.87920808 0.87277272 0.91078074 ... 0.97246425 0.         0.86405338]
 [0.67340185 0.91170124 1.         ... 0.94329862 0.86405338 0.        ]]
[[0.         0.72655859 0.71110326 ... 1.         1.         1.        ]
 [0.72655859 0.         0.78844369 ... 1.         0.90661408 1.        ]
 [0.71110326 0.78844369 0.         ... 1.         1.         1.        ]
 ...
 [1.         1.         1.         ... 0.         1.         1.        ]
 [1.         0.90661408 1.         ... 1.         0.         1.        ]
 [1.         1.         1.         ... 1.         1.         0.        ]]
yuce***********
[[0.38285028 0.40383315 0.41990713 ... 0.47385458 0.46267752 0.47114813]
 [0.0839331  0.09477321 0.09129674 ... 0.09362053 0.09501009 0.09518144]
 [0.06516871 0.06845461 0.06684125 ... 0.06331703 0.06697337 0.06722189]
 ...
 [0.0268516  0.0359455  0.03502679 ... 0.04058066 0.03970251 0.04045211]
 [0.13417963 0.14283188 0.14976465 ... 0.15155925 0.15103048 0.15288519]
 [0.20520577 0.20295445 0.22561216 ... 0.25758525 0.24941277 0.25580012]]
[[ 1.64300223  0.57801719  0.5136358  ...  0.32376338  0.32351587
   0.32119798]
 [ 1.38470596  0.25382729  0.15109705 ... -0.07179432 -0.07053171
  -0.07374653]
 [ 1.3893305   0.2226973   0.12585267 ... -0.10138413 -0.09947328
  -0.1026983 ]
 ...
 [ 1.23145311  0.18601276  0.08755609 ... -0.12392211 -0.12315057
  -0.1262216 ]
 [ 1.4340729   0.295668    0.21700738 ... -0.00697219 -0.00611205
  -0.0089443 ]
 [ 1.45976555  0.35963021  0.30179446 ...  0.10529929  0.10523553
   0.10279947]]
User-based CF RMSE: 3.1228749648419565
Item-based CF RMSE: 3.4501665337217244
The sparsity level of MovieLens100K is 93.7%
User-based CF MSE: 2.7175119312541027

你可能感兴趣的:(Movie推荐系统)