电影评分数据集是推荐系统经常用到的经典数据集,下面给出下载链接:
链接: https://pan.baidu.com/s/1oKEIT2GKoGrY5NNgOPd4fA?pwd=wf6q 提取码: wf6q
复制这段内容后打开百度网盘手机App,操作更方便哦
import os
import panda as pd
import numpy as np
DATA_PATH = 'D:/p/ml-latest-small/ratings.csv' #表格里是:userId,movieId,rating,timestamp
CACHE_DIR = 'D:/p/cache/'
def load_data(data_path):
"""
加载数据
Param: data_path:数据集路径
cache_path:数据集缓存路径
Return:用户——物品评分矩阵
"""
cache_path = os.path.join(CACHE_DIR,'rating_mateix.cahe')
print('开始加载数据集')
if os.path.exists(cache_path):
print('加载缓存中...') #pickle是python的一种储存数据方式可以节约空间,可以加快读取速度;
ratings_matrix = pd.read_pickle(cache_path) #pd.read_pickle()函数用于加载 pickle;
print('从缓存加载数据集完毕.')
else:
print('加载新数据中...')
#设置要加载的数据字段的类型
dtype = {'userId':np.int32,'movieId':np.int32,'rating':np.float32}
#加载数据,我们只利用前三列数据
ratings = pd.read_csv(data_path,dtype=dtype,usecols=range(3))
#透视表,将其转换成User-movie评分矩阵
ratings_matrix = ratings.pivot_table(index=['userId'],columns=['movieId'],values=['rating'])
#存入缓存文件
ratings_matrix.to_pickle(cache_path)
print(ratings_matrix)
print('数据集加载完毕')
return ratings_matrix
if __name__ == '__main__' :
ratings_matrix = load_data(DATA_PATH)
print(ratings_matrix)
运行结果:
开始加载数据集.
加载缓存中...
从缓存加载数据集完毕.
rating
movieId 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ... 190215 190219 190221 191005 193565 193567 193571 193573 193579 193581 193583 193585 193587 193609
userId
1 4.0 NaN 4.0 NaN NaN 4.0 NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
2 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
3 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
4 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
5 4.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
606 2.5 NaN NaN NaN NaN NaN 2.5 NaN NaN NaN 2.5 NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
607 4.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN 3.0 NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
608 2.5 2.0 2.0 NaN NaN NaN NaN NaN NaN 4.0 NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
609 3.0 NaN NaN NaN NaN NaN NaN NaN NaN 4.0 NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
610 5.0 NaN NaN NaN NaN 5.0 NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
[610 rows x 9724 columns]
def computer_pearson_similarity(ratings_matrix,based='user'):
"""
计算相似度
Param:rating_matrix:评分矩阵
based:user or item:基于用户还是基于项目
Return:similarity:相似度矩阵
"""
user_similarity_cache_path = os.path.join(CACHE_DIR,'user_similarity.cache')
item_similarity_cache_path = os.path.join(CACHE_DIR,'item_similarity.cache')
#基于皮尔逊相关系数计算相似度
#用户相似度
if based == 'user':
if os.path.exists(user_similarity_cache_path):
print('正从缓存加载用户相似度矩阵')
similarity = pd.read_pickle(user_similarity_cache_path)
else:
print('开始计算用户相似度矩阵')
similarity = ratings_matrix.T.corr()
similarity.to_pickle(user_similarity_cache_path)
elif based == 'item':
if os.path.exists(item_similarity_cache_path):
print('正从缓存加载物品相似度矩阵')
similarity = pd.read_pickle(item_similarity_cache_path)
else:
print('开始计算物品相似度矩阵')
similarity = ratings_matrix.corr()
similarity.to_pickle(item_similarity_cache_path)
else:
raise Exception("Unhandled 'based' value: %s" %based)
print('相似度矩阵加载完毕')
return similarity
if __name__ == '__main__' :
ratings_matrix = load_data(DATA_PATH)
user_similar = computer_pearson_similarity(ratings_matrix,based='user')
print(user_similar)
item_similar = computer_pearson_similarity(ratings_matrix,based='item')
print(item_similar)
运行结果:
正从缓存加载用户相似度矩阵
相似度矩阵加载完毕
userId 1 2 3 4 5 6 7 8 9 ... 602 603 604 605 606 607 608 609 610
userId ...
1 1.000000 NaN 0.079819 0.207983 0.268749 -0.291636 -0.118773 0.469668 0.918559 ... -1.597727e-16 -0.061503 -0.407556 -0.164871 0.066378 0.174557 0.268070 -0.175412 -0.032086
2 NaN 1.000000 NaN NaN NaN NaN -0.991241 NaN NaN ... NaN -1.000000 NaN NaN 0.583333 NaN -0.125000 NaN 0.623288
3 0.079819 NaN 1.000000 NaN NaN NaN NaN NaN NaN ... NaN 0.433200 NaN NaN -0.791334 -0.333333 -0.395092 NaN 0.569562
4 0.207983 NaN NaN 1.000000 -0.336525 0.148498 0.542861 0.117851 NaN ... 3.966413e-01 0.090090 -0.080296 0.400124 0.144603 0.116518 -0.170501 -0.277350 -0.043786
5 0.268749 NaN NaN -0.336525 1.000000 0.043166 0.158114 0.028347 NaN ... 1.533034e-01 0.234743 0.067791 -0.364156 0.244321 0.231080 -0.020546 0.384111 0.040582
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
606 0.066378 0.583333 -0.791334 0.144603 0.244321 -0.049192 0.137771 0.253582 0.572700 ... 1.406134e-01 0.318473 0.682949 0.167062 1.000000 0.114191 0.240842 0.533002 0.389185
607 0.174557 NaN -0.333333 0.116518 0.231080 0.255639 0.402792 0.251280 NaN ... 2.172105e-01 0.192787 0.035806 -0.299641 0.114191 1.000000 0.200814 0.190117 0.106605
608 0.268070 -0.125000 -0.395092 -0.170501 -0.020546 0.125428 0.008081 0.434423 0.336625 ... 2.976461e-01 0.086423 0.053986 -0.075673 0.240842 0.200814 1.000000 0.488929 0.147606
609 -0.175412 NaN NaN -0.277350 0.384111 0.193649 0.420288 0.141860 NaN ... 1.885115e-01 0.343303 0.641624 -0.550000 0.533002 0.190117 0.488929 1.000000 -0.521773
610 -0.032086 0.623288 0.569562 -0.043786 0.040582 0.115580 0.341233 0.167931 0.615638 ... 4.926267e-02 0.270908 0.310611 0.462274 0.389185 0.106605 0.147606 -0.521773 1.000000
[610 rows x 610 columns]
正从缓存加载物品相似度矩阵
相似度矩阵加载完毕
rating ...
movieId 1 2 3 4 5 6 7 8 9 10 11 ... 191005 193565 193567 193571 193573 193579 193581 193583 193585 193587 193609
movieId ...
rating 1 1.000000 0.330978 0.487109 1.000000 0.310971 0.106465 0.208402 0.968246 0.095913 -0.021409 0.206812 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
2 0.330978 1.000000 0.419564 NaN 0.562791 0.163510 0.430261 0.415227 0.277350 0.016626 0.466415 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
3 0.487109 0.419564 1.000000 NaN 0.602266 0.345069 0.554088 0.333333 0.458591 -0.050276 0.218322 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
4 1.000000 NaN NaN 1.000000 0.654654 NaN 0.203653 NaN NaN 0.870388 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
5 0.310971 0.562791 0.602266 0.654654 1.000000 0.291302 0.609119 0.555556 0.319173 0.218263 0.341227 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
193581 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
193583 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
193585 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
193587 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
193609 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
[9724 rows x 9724 columns]
评分预测公式:
p r e d ( u , i ) = r ^ u i = ∑ s i m ( u , v ) ∗ r u i ∑ ∣ s i m ( u , v ) ∣ pred(u,i)=\hat{r}_{ui}=\frac{\sum{sim(u,v)*r_{ui}}}{\sum{\vert sim(u,v)\vert}} pred(u,i)=r^ui=∑∣sim(u,v)∣∑sim(u,v)∗rui
def predict(uid,iid,ratings_matrix,user_similar):
"""
预测给定用户规定物品的评分
Param:
uid:用户id
iid:项目id
rating_matrix:评分矩阵
user_similar:用户相似度矩阵
"""
print("开始预测用户<%s>对电影<%s>的评分"%(uid,iid))
#1.找出uid的相似用户(similar_users:相似用户的相似度矩阵)
similar_users = user_similar[uid].drop([uid]).dropna() #去掉自己并且去掉缺失值
#2.找出uid的相似用户的正相关用户(similar_users:相似用户的正相关用户的相似度矩阵)
similar_users = similar_users.where(similar_users>0).dropna()
if similar_users.empty is True:
raise Exception("用户<%d>没有相似的用户" % uid)
# print(similar_users)
#3.找出能提供评分的正相关用户(ids:能提供评分的正相关用户列表)
ids = set(ratings_matrix.iloc[:,iid-1].dropna().index)&set(similar_users.index) #项目那列有评分的用户的索引 and 正相关相似用户
# print(ids)
#4. finally_similar_users:能提供评分的用户的相似度矩阵
finally_similar_users = similar_users.loc[list(ids)]
# print(finally_similar_users)
#3.结合uid用户的相似用户的相似度预测uid对iid物品的评分
sum_up = 0 #分子
sum_down = 0 #分母
for sim_uid,similarity in finally_similar_users.iteritems():
sim_user_rated_movies = ratings_matrix.loc[sim_uid].dropna()
sim_user_rating_for_item = sim_user_rated_movies[uid]
sum_up += similarity*sim_user_rating_for_item
sum_down += similarity
predict_rating = sum_up/(sum_down+0.01)
return predict_rating
def predict_all(uid,ratings_matrix,user_similar):
"""
预测全部评分
"""
item_ids = ratings_matrix.loc[uid].dropna().index
for iid in item_ids:
rating = predict(uid,iid,ratings_matrix,user_similar)
print(rating)
注:上网查资料解释一下loc的用法,按标签去取,【】中是先行后列;
iloc是按位置取,【】n行n列;
1.用户相似度矩阵
user_similar:
userId 1 2 3 4 5 6 7 8 9 ... 602 603 604 605 606 607 608 609 610
userId ...
1 1.000000 NaN 0.079819 0.207983 0.268749 -0.291636 -0.118773 0.469668 0.918559 ... -1.597727e-16 -0.061503 -0.407556 -0.164871 0.066378 0.174557 0.268070 -0.175412 -0.032086
2 NaN 1.000000 NaN NaN NaN NaN -0.991241 NaN NaN ... NaN -1.000000 NaN NaN 0.583333 NaN -0.125000 NaN 0.623288
3 0.079819 NaN 1.000000 NaN NaN NaN NaN NaN NaN ... NaN 0.433200 NaN NaN -0.791334 -0.333333 -0.395092 NaN 0.569562
4 0.207983 NaN NaN 1.000000 -0.336525 0.148498 0.542861 0.117851 NaN ... 3.966413e-01 0.090090 -0.080296 0.400124 0.144603 0.116518 -0.170501 -0.277350 -0.043786
5 0.268749 NaN NaN -0.336525 1.000000 0.043166 0.158114 0.028347 NaN ... 1.533034e-01 0.234743 0.067791 -0.364156 0.244321 0.231080 -0.020546 0.384111 0.040582
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
606 0.066378 0.583333 -0.791334 0.144603 0.244321 -0.049192 0.137771 0.253582 0.572700 ... 1.406134e-01 0.318473 0.682949 0.167062 1.000000 0.114191 0.240842 0.533002 0.389185
607 0.174557 NaN -0.333333 0.116518 0.231080 0.255639 0.402792 0.251280 NaN ... 2.172105e-01 0.192787 0.035806 -0.299641 0.114191 1.000000 0.200814 0.190117 0.106605
608 0.268070 -0.125000 -0.395092 -0.170501 -0.020546 0.125428 0.008081 0.434423 0.336625 ... 2.976461e-01 0.086423 0.053986 -0.075673 0.240842 0.200814 1.000000 0.488929 0.147606
609 -0.175412 NaN NaN -0.277350 0.384111 0.193649 0.420288 0.141860 NaN ... 1.885115e-01 0.343303 0.641624 -0.550000 0.533002 0.190117 0.488929 1.000000 -0.521773
610 -0.032086 0.623288 0.569562 -0.043786 0.040582 0.115580 0.341233 0.167931 0.615638 ... 4.926267e-02 0.270908 0.310611 0.462274 0.389185 0.106605 0.147606 -0.521773 1.000000
2.用户正相关相似用户相似度矩阵
similar_users:
userId
3 0.079819
4 0.207983
5 0.268749
8 0.469668
9 0.918559
...
600 0.253649
601 0.091574
606 0.066378
607 0.174557
608 0.268070
Name: 1, Length: 383, dtype: float64
3.对iid项目有评分的相似用户:
ids:
{514, 517, 5, 522, 524, 525, 15, 17, 18, 19, 21, 533, 27, 31, ...}
4.对iid有评分的相似用户的相似度矩阵
finally_similar_users:
userId
514 0.047894
517 0.080181
5 0.268749
522 0.046613
524 0.384955
...
484 0.509886
488 0.332169
490 0.166961
504 0.342997
509 0.028028
Name: 1, Length: 158, dtype: float64
#4.推荐结果
完整代码如下:
import os
import pandas as pd
import numpy as np
DATA_PATH = 'D:/p/ml-latest-small/ratings.csv'
CACHE_DIR = 'D:/p/cache/'
MOVIE_PATH = 'D:/p/ml-latest-small/movies.csv'
def load_data(data_path):
"""
加载数据
Param: data_path:数据集路径
cache_path:数据集缓存路径
Return:用户——物品评分矩阵
"""
#数据集缓存地址
cache_path = os.path.join(CACHE_DIR,'rating_matrix.cache') #os.path.join()函数用于路径拼接文件路径
print('开始加载数据集.')
if os.path.exists(cache_path):
print('加载缓存中...')
ratings_matrix = pd.read_pickle(cache_path) #pd.read_pickle()函数用于从文件中加载 pickle的 Pandas对象(或任何对象)
print('从缓存加载数据集完毕.')#什么是pickle? pickle可以将对象以文件的形式存放在磁盘上,python中几乎所有的数据类型(列表,字典,集合,类等)都可以用pickle来序列化。
else:
print('加载新数据中...')
#设置要加载的数据字段的类型
dtype = {'userId':np.int32,'movieId':np.int32,'rating':np.float32}
#加载数据,我们只利用前三列数据
ratings = pd.read_csv(data_path,dtype=dtype,usecols=range(3))
#透视表,将其转换成User-movie评分矩阵
ratings_matrix = ratings.pivot_table(index=['userId'],columns=['movieId'],values=['rating'])
#存入缓存文件
ratings_matrix.to_pickle(cache_path)
# print(ratings_matrix)
print('数据集加载完毕')
return ratings_matrix
def computer_pearson_similarity(ratings_matrix,based='user'):
"""
计算相似度
Param:rating_matrix:评分矩阵
based:user or item
Return:相似度矩阵
"""
user_similarity_cache_path = os.path.join(CACHE_DIR,'user_similarity.cache')
item_similarity_cache_path = os.path.join(CACHE_DIR,'item_similarity.cache')
#基于皮尔逊相关系数计算相似度
#用户相似度
if based == 'user':
if os.path.exists(user_similarity_cache_path):
print('正从缓存加载用户相似度矩阵')
similarity = pd.read_pickle(user_similarity_cache_path)
else:
print('开始计算用户相似度矩阵')
similarity = ratings_matrix.T.corr() #计算相似度
similarity.to_pickle(user_similarity_cache_path)
elif based == 'item':
if os.path.exists(item_similarity_cache_path):
print('正从缓存加载物品相似度矩阵')
similarity = pd.read_pickle(item_similarity_cache_path)
else:
print('开始计算物品相似度矩阵')
similarity = ratings_matrix.corr()
similarity.to_pickle(item_similarity_cache_path)
else:
raise Exception("Unhandled 'based' value: %s" %based)
print('相似度矩阵加载完毕')
return similarity
def predict(uid,iid,ratings_matrix,user_similar):
"""
预测给定用户规定物品的评分
Param:uid:用户id
iid:项目id
rating_matrix:评分矩阵
user_similar:用户相似度矩阵
"""
# print("开始预测用户<%s>对电影<%s>的评分"%(uid,iid))
#1.找出uid的相似用户
similar_users = user_similar[uid].drop([uid]).dropna() #去掉自己并且去掉缺失值
#相似用户筛选规则:正相关的用户
similar_users = similar_users.where(similar_users>0).dropna()
if similar_users.empty is True:
raise Exception("用户<%d>没有相似的用户" % uid)
# print(similar_users)
#2.从uid用户的正相关的用户中筛选出对iid物品有评分记录的近邻用户 ids
#iid项目中和用户有评分的取出索引 and 正相关的用户
ids = set(ratings_matrix.iloc[:,iid-1].dropna().index)&set(similar_users.index) #ratings_matrix[iid]拿的是列
# print(ids)
finally_similar_users = similar_users.loc[list(ids)]
# print(finally_similar_users)
#3.结合uid用户的相似用户的相似度预测uid对iid物品的评分
sum_up = 0 #分子
sum_down = 0 #分母
for sim_uid,similarity in finally_similar_users.iteritems():
sim_user_rated_movies = ratings_matrix.loc[sim_uid].dropna()
sim_user_rating_for_item = sim_user_rated_movies[uid]
sum_up += similarity*sim_user_rating_for_item
sum_down += similarity
predict_rating = sum_up/(sum_down+0.01)
return predict_rating
def predict_all(uid,ratings_matrix,user_similar):
"""
预测全部评分
"""
Ratings=[]
d={}
item_ids = ratings_matrix.loc[uid].dropna().index
for iid in item_ids:
rating = predict(uid,iid[uid],ratings_matrix,user_similar)
Ratings.append(rating)
# print(rating)
d[iid[uid]]=rating
return d
def result(N,d):
m=[]
dtype = {'movieId':np.int32,'name':np.string_}
moives = pd.read_csv(MOVIE_PATH,dtype=dtype,usecols=range(2))
d_1 = list(d.items())
d = dict(sorted(d_1,key = lambda x:x[1],reverse=True))
# print(d)
for i, (k, v) in enumerate(d.items()):
if i in range(0, N):
print(k, v)
print(moives[moives.movieId == k])
if __name__ == '__main__' :
Ratings=[]
ratings_matrix = load_data(DATA_PATH)
user_similar = computer_pearson_similarity(ratings_matrix,based='user')
# item_similar = computer_pearson_similarity(ratings_matrix,based='item')
d = predict_all(1,ratings_matrix,user_similar)
# print(d)
result(5,d)
对字典进行排序:
>>> my_dict = {'a':300,'c':100,'b':200}
>>> list_1 = list(my_dict.items())
>>> list_1
[('a', 300), ('c', 100), ('b', 200)]
# 对字典按照key值进行排序,并返回排序后的新字典
>>> my_dict_sortbykey = dict(sorted(list_1,key = lambda x:x[0]))
>>> my_dict_sortbykey
{'a': 300, 'b': 200, 'c': 100}
# 对字典按照value值进行排序,并返回排序后的新字典
>>> my_dict_sortbyvalue = dict(sorted(list_1,key = lambda x:x[1]))
>>> my_dict_sortbyvalue
{'c': 100, 'b': 200, 'a': 300}
# 提取字典的所有keys并进行排序(实质就是sorted函数应用于简单元素的列表)
>>> my_dict_sortedkeys = sorted(my_dict.keys())
>>> my_dict_sortedkeys
['a', 'b', 'c']
# 提取字典的所有values并进行排序(实质就是sorted函数应用于简单元素的列表)
>>> my_dict_sortedvalues = sorted(my_dict.values())
>>> my_dict_sortedvalues
[100, 200, 300]
注:目前我们是用pandas,但pandas无法支撑大数据量的运算,我们数据集的数据是非常小的,工业上一般回使用spark,mapreduce等分布式计算框架来计算。