网页版—点击这里
数据及介绍
MovieLens是推荐系统常用的数据集
MovieLens数据集中,用户对自己看过的电影进行评分,分值为1-5.
MovieLens包括两个大小不同的库。适用于不同规模的算法,
小规模是943个用户对1682部电影做约10000次评分的数据
大规模的是6040个用户对3900部电影做大约100万次评分
导入数据
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"
%matplotlib inline
import numpy as np
import pandas as pd
#设置数据列名
header = ["user_id","item_id","rating","timesamp"]
src_data = pd.read_csv("./ml-100k/u.data",sep='\t',names=header)
src_data.head()
查看结构
src_data.info()
src_data.describe()
查看用户去重后的个数
src_data.user_id.nunique()
查看物品去重后的个数
src_data.item_id.nunique()
#检查事都有重复用户物品打分记录
src_data.duplicated(subset=["user_id","item_id"]).sum()
#每一个电影对应的客户数
item_id_usercnt = src_data.groupby("item_id").count()["user_id"]
item_id_usercnt
画图
import matplotlib.pyplot as plt
plt.rcParams["font.sans-serif"]=['SimHei'] # 用于正常显示中文标签
plt.rcParams['axes.unicode_minus']=False # 用来正常显示负号
plt.title('每个物品对应的用户数量')
plt.xlabel("评价的客户数/人")
plt.ylabel("被评论的电影数")
plt.hist(item_id_usercnt.values)
###每个物品对应的用户数,(10分位,20分位,30分位。。。。100分位)
np.arange(0,1.1,step=0.1)
item_id_usercnt.quantile(q=np.arange(0,1.1,step=0.1))
#每个用户评价电影的个数
user_id_usercnt = src_data.groupby('user_id').count()["item_id"]
user_id_usercnt.values
import matplotlib.pyplot as plt
#画图
plt.hist(user_id_usercnt.values)
user_id_usercnt.quantile(q=np.arange(0,1.1,step=0.1))
n_users = src_data.user_id.nunique()
n_items = src_data.item_id.nunique()
print(n_users)
print(n_items)
构建用户-电影评分矩阵
src_data_matrix = np.zeros((n_users,n_items))
# print(src_data_matrix) 产生一个类似的全是0元素的矩阵
#src_data.itertuples()###将DataFrame转为元组##############
for line in src_data.itertuples():
# print(line)
src_data_matrix[line[1]-1,line[2]-1] = line[3] #将电影和评分数给line【3】
# print(line[3])
src_data_matrix
src_data.itertuples
判断矩阵的稀疏性
sparsity = round(len(src_data_matrix.nonzero() \
[1])/float(n_users*n_items),3)
sparsity #非常稀疏
#使用sklearn.metrics.pairwise中的cosine
from sklearn.metrics.pairwise import pairwise_distances
item_similarity_m = pairwise_distances(src_data_matrix.T,metric="cosine")
item_similarity_m.shape
数据探索
1、电影相似矩阵
#非0值得比例
round(np.sum(item_similarity_m>0)
/float(item_similarity_m.shape[0]
*item_similarity_m.shape[1]),3)
#相似矩阵为对称矩阵
item_similarity_m[0:5,0:5].round(2)
#因为是对称的,分析上三角,得到分位数
item_similarity_m_triu = np.triu(item_similarity_m,k=1)
item_sim_nonzero = np.round(item_similarity_m_triu[item_similarity_m_triu.nonzero()],3)
np.percentile(item_sim_nonzero,np.arange(0,101,10))
#相似度得分比较大,相似度没有区分性
"""
#知识点:上三角np.triu
arr = np.linspace(1,9,9).reshape(3,3)
np.triu(arr,k=1)
"""
#########预测
# 得到预测矩阵P
user_item_prediction = src_data_matrix.dot(item_similarity_m)/ np.array([np.abs(item_similarity_m).sum(axis=1)])
user_item_prediction
# 只取预测数据集中有评分的数据集,进行评估
from sklearn.metrics import mean_squared_error
from math import sqrt
prediction_flatten = user_item_prediction[src_data_matrix.nonzero()]
user_item_matrix_flatten = src_data_matrix[src_data_matrix.nonzero()]
sqrt(mean_squared_error(prediction_flatten, user_item_matrix_flatten))
# 测试数据集构建
test_data_matrix = np.zeros((n_users, n_items))
for line in src_data.itertuples():
test_data_matrix[line[1]-1, line[2]-1] = line[3]
# 预测矩阵
item_prediction = src_data_matrix.dot(item_similarity_m) / np.array([np.abs(item_similarity_m).sum(axis=1)])
# 只取预测数据集中有评分的数据集
from sklearn.metrics import mean_squared_error
from math import sqrt
prediction_flatten = item_prediction[test_data_matrix.nonzero()]
test_data_matrix_flatten = test_data_matrix[test_data_matrix.nonzero()]
sqrt(mean_squared_error(prediction_flatten, test_data_matrix_flatten))
2、单模型结果提升
# 相似度算法指定为欧氏距离
item_similarity_m = pairwise_distances(src_data_matrix.T, metric='euclidean')
item_similarity_m
from sklearn.model_selection import train_test_split
train_data, test_data = train_test_split(src_data, test_size=0.2)
#导入模块
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"
import numpy as np
import pandas as pd
header = ['user_id', 'item_id', 'rating', 'timestamp']
src_data = pd.read_csv('ml-100k/u.data', sep='\t', names=header)
src_data.head()
# 用户、物品数统计
n_users = src_data.user_id.nunique()
n_items = src_data.item_id.nunique()
# 训练集、测试集分离
from sklearn.model_selection import train_test_split
train_data, test_data = train_test_split(src_data, test_size=0.3)
# 训练集 用户-物品矩阵
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]
1、用户相似度矩阵
#采用余弦距离
from sklearn.metrics.pairwise import pairwise_distances
user_similarity_m = pairwise_distances(train_data_matrix,metric="cosine")
2、数据探索
2.1、用户相似矩阵
#物品相似矩阵,行列
user_similarity_m.shape
#非0 比例
#round四舍五入
round(np.sum(user_similarity_m>0)/float(user_similarity_m.shape[0]
*user_similarity_m.shape[1]),3)
# 相似矩阵为对称矩阵
user_similarity_m[0:5, 0:5].round(2)
#现在我们分析上三角,得到等分位数
user_similarity_m_triu = np.triu(user_similarity_m,k=1)
item_sim_nonzero2 = np.round(user_similarity_m_triu[
user_similarity_m_triu.nonzero()
],3)
np.percentile(item_sim_nonzero2,np.arange(0,101,10))
"""
##############可以看出相似度得分都偏大,相似度没有区分性
"
# 得到预测矩阵P
mean_user_rating = train_data_matrix.mean(axis=1)
ratings_diff = (train_data_matrix - mean_user_rating[:, np.newaxis]) #升维度
user_prediction = mean_user_rating[:, np.newaxis] + \
user_similarity_m.dot(ratings_diff) / \
np.array([np.abs(user_similarity_m).sum(axis=1)]).T
2.2、训练数据
from sklearn.metrics import mean_squared_error
from math import sqrt
prediction_flatten = user_prediction[train_data_matrix.nonzero()]
train_data_matrix_flatten = train_data_matrix[train_data_matrix.nonzero()]
sqrt(mean_squared_error(prediction_flatten, train_data_matrix_flatten))
2.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]
2.4、只取预测数据集中有评分的数据集
from sklearn.metrics import mean_squared_error
from math import sqrt
prediction_flatten = user_prediction[test_data_matrix.nonzero()]
test_data_matrix_flatten = test_data_matrix[test_data_matrix.nonzero()]
sqrt(mean_squared_error(prediction_flatten, test_data_matrix_flatten))
3、提升
#####相似度算法指定为欧氏距离
user_similarity_m = pairwise_distances(train_data_matrix, \
metric='euclidean')
train_data, test_data = train_test_split(src_data, test_size=0.2)
###3.3、基于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)
svd_prediction = np.dot(np.dot(u, s_diag_matrix), vt)
u.shape
s.shape
vt.shape
s_diag_matrix.shape
svd_prediction.shape
"""
(943, 20)
(20,)
(20, 1682)
(20, 20)
(943, 1682)
"""
# 查看预测矩阵值分布
pd.Series(np.percentile(svd_prediction, np.arange(0, 101, 10))).map("{:.2f}".format)
# 查看训练数据矩阵值分布
pd.Series(np.percentile( train_data_matrix, np.arange(0, 101, 10))).map("{:.2f}".format)
# 查看训练数据矩阵非0值分布
pd.Series(np.percentile( train_data_matrix[train_data_matrix.nonzero()],\
np.arange(0, 101, 10))).map("{:.2f}".format)
## 预测值限定最小值和最大值
# 将预测值中小于0的值,赋值为0
svd_prediction[svd_prediction<0] = 0
# 将预测值中大于5的值,赋值为5
svd_prediction[svd_prediction>5] = 5
评估
# 只取预测数据集中有评分的数据集,进行评估
from sklearn.metrics import mean_squared_error
from math import sqrt
prediction_flatten = svd_prediction[train_data_matrix.nonzero()]
train_data_matrix_flatten = train_data_matrix[train_data_matrix.nonzero()]
sqrt(mean_squared_error(prediction_flatten, train_data_matrix_flatten))
# 只取预测数据集中有评分的数据集
from sklearn.metrics import mean_squared_error
from math import sqrt
prediction_flatten = svd_prediction[test_data_matrix.nonzero()]
test_data_matrix_flatten = test_data_matrix[test_data_matrix.nonzero()]
sqrt(mean_squared_error(prediction_flatten, test_data_matrix_flatten))