推荐系统系列文章目录
Part1 推荐系统基础
Part2 Movienles介绍
前言
如果说互联网的目标就是连接一切,那么推荐系统的作用就是建立更加有效率的连接,推荐系统可以更有效率的连接用户与内容和服务,节约了大量的时间和成本。如果把推荐系统简单拆开来看,推荐系统主要是由数据、算法、架构三个方面组成。
今天来介绍一下Movielens 1M数据集。
提示:以下是本篇文章正文内容,下面案例可供参考
一、README
该文件是对该数据集的整体介绍。该文件内容表示,该数据集包含了6040个用户对3900部电影的1000209条评分记录。关于每个文件的内容和格式,可以参考该文件或阅读下面的内容。
二、rating.dat
该文件的内容是用户对电影的评分记录,包含了1000209条数据,数据格式如下:
1::1193::5::978300760
该条记录对应列指代的是:UserId::MovieID::Rating::Timestamp,传达的内容是:ID为1的用户在时间戳为978300760时对ID为1193的这部电影打了5分。
其中,UserID的范围是1~6040,MovieID的范围是1-3952,评分最高为5分,时间戳以秒为单位。在所有的记录中,每个用户至少有20条记录。
代码如下:
# _*_coding utf-8_*_
# 开发团队: DMU
# 开发人员: $(USER)
# 开发时间: $(DATE)$(TIME)
# 文件名: $(NAME).py
# 开发工具: $(PRODUCT_NAME)
import matplotlib.pyplot as plt
import pandas as pd
# 用来正常显示中文标签
plt.rcParams["font.sans-serif"] = ["SimHei"]
# 用来正常显示负号
plt.rcParams['axes.unicode_minus'] = False
def getRatings(file_path):
rates = pd.read_csv(
file_path,
header=None,
sep='::',
names=['userID','movieID','rate','timestamp'],
)
print('userID的范围是:<{},{}>'.format(min(rates['userID']),max(rates['userID'])))
print('movieID的范围是:<{},{}>'.format(min(rates['movieID']),max(rates['movieID'])))
print('评分的范围是:<{},{}>'.format(min(rates['rate']),max(rates['rate'])))
print('数据的总条数是:\n{}'.format(rates.count()))
print('数据的前五条记录是:\n{}'.format(rates.head(5)))
df = rates['userID'].groupby(rates['userID'])
print('最少评分记录最少条数为:{}'.format(df.count().min()))
scores = rates['rate'].groupby(rates['rate']).count()
for x,y in zip(scores.keys(),scores.values):
plt.text(x,y+2,'%.0f'%y,ha='center',va='bottom',fontsize=12)
plt.bar(scores.keys(),scores.values,fc='r',tick_label=scores.keys())
plt.xlabel('评分分数')
plt.ylabel('对应的人数')
plt.title('评分分数对应人数统计')
plt.show()
if __name__ == '__main__':
getRatings('../Dateset/ml-1m/ratings.dat')
结果如下:
userID的范围是:<1,6040>
movieID的范围是:<1,3952>
评分的范围是:<1,5>
数据的总条数是:
userID 1000209
movieID 1000209
rate 1000209
timestamp 1000209
dtype: int64
数据的前五条记录是:
userID movieID rate timestamp
0 1 1193 5 978300760
1 1 661 3 978302109
2 1 914 3 978301968
3 1 3408 4 978300275
4 1 2355 5 978824291
最少评分记录最少条数为:20
Process finished with exit code 0
三、movies.dat
该文件内容表示的是电影的相关信息,每条(即每行)数据的形式如下:
1::Toy Story(1905)::Animation|Children's|Comedy
其中的列数据以“::”进行分割。第一列为电影ID,第二列为电影名字,第三列为电影的类型(类型以"|"分割)。
通过以下代码来查看数据的总条数和每种电影类型的统计分布图。
在这里插入代码片
import matplotlib.pyplot as plt
import pandas as pd
def getMovies(file_path):
movies = pd.read_table(
file_path,
header=None,
sep='::',
names=['movieID','title','genres'],
encoding='unicode_escape'
)
print('moviesID的范围是<{},{}>'.format(min(movies['movieID']),max(movies['movieID'])))
print('数据总条数为:\n{}'.format(movies.count()))
moviesDict = dict()
for line in movies['genres'].values:
for one in line.split('|'):
moviesDict.setdefault(one,0)
moviesDict[one] += 1
print('电影类型的总数为:{}'.format(len(moviesDict)))
print('电影的类型分别是:{}'.format(moviesDict.keys()))
print(moviesDict)
newMD = sorted(moviesDict.items(),key=lambda x:x[1],reverse=True)
labels = [newMD[i][0] for i in range(len(newMD))]
values = [newMD[i][1] for i in range(len(newMD))]
explode = [x*0.01 for x in range(len(newMD))]
plt.axes(aspect=1)
plt.pie(
x=values,
labels=labels,
explode=explode,
autopct='%3.lf %%',
shadow=False,
labeldistance=1.1,
startangle=0,
pctdistance=0.8,
center=(-1,0),
)
plt.legend(
loc=7,
bbox_to_anchor=(1.3,1.0),
ncol=3,
fancybox=True,
shadow=True,
fontsize=6
)
plt.show()
结果如下:
在这里插入代码片
moviesID的范围是<1,3952>
数据总条数为:
movieID 3883
title 3883
genres 3883
dtype: int64
电影类型的总数为:18
电影的类型分别是:dict_keys(['Animation', "Children's", 'Comedy', 'Adventure', 'Fantasy', 'Romance', 'Drama', 'Action', 'Crime', 'Thriller', 'Horror', 'Sci-Fi', 'Documentary', 'War', 'Musical', 'Mystery', 'Film-Noir', 'Western'])
{'Animation': 105, "Children's": 251, 'Comedy': 1200, 'Adventure': 283, 'Fantasy': 68, 'Romance': 471, 'Drama': 1603, 'Action': 503, 'Crime': 211, 'Thriller': 492, 'Horror': 343, 'Sci-Fi': 276, 'Documentary': 127, 'War': 143, 'Musical': 114, 'Mystery': 106, 'Film-Noir': 44, 'Western': 68}
电影类型的饼图如下:
四、users.dat
该文件的内容是用户的相关信息,每条(即每行)数据的形式如下:
1::F::1::10::48067
其中,列数据以“::”进行分割。第一列是用户id,第二列是用户性别,第三列是用户年龄,第四列表示用户职业,第五列表示的是压缩编码。
其中,年龄1对应1~18岁(不包含18岁),18表示18-24岁,25表示25-34岁,35表示35-44岁,45表示45-49岁,50表示50-55岁,56表示大于等于56岁。
同样,不同的职业编号对应着不同的岗位。
对用户的性别,年龄分布信息进行统计,代码如下:
def getUsers(file_path):
users = pd.read_table(
file_path,
header=None,
sep='::',
names=['userID','gender','age','Occupation','zip-code'],
)
print('userID的范围是:<{},{}>'.format(min(users['userID']),max(users['userID'])))
print("数据的总条数是:\n{}".format(users.count()))
usersGender = users['gender'].groupby(users['gender']).count()
print(usersGender)
plt.axes(aspect=1)
plt.pie(
x=usersGender.values,
labels=usersGender.keys(),
autopct='%3.1f %%'
)
plt.legend(bbox_to_anchor=(1.0,1.0))
plt.show()
usersAge = users['age'].groupby(users['age']).count()
print(usersAge)
plt.plot(
usersAge.keys(),
usersAge.values,
label='用户年龄信息展示',
linewidth=3,
color='r',
marker='o',
markerfacecolor='blue',
markersize=12,
)
for x,y in zip(usersAge.keys(),usersAge.values):
plt.text(x,y+10,'%.0f'%y,ha='center',va='bottom',fontsize=12)
plt.xlabel('用户年龄')
plt.ylabel('年龄段对应的人数')
plt.title('用户年龄段人数统计')
plt.show()
运行代码,结果如下:
userID的范围是:<1,6040>
数据的总条数是:
userID 6040
gender 6040
age 6040
Occupation 6040
zip-code 6040
dtype: int64
gender
F 1709
M 4331
Name: gender, dtype: int64
age
1 222
18 1103
25 2096
35 1193
45 550
50 496
56 380
Name: age, dtype: int64
Process finished with exit code 0
用户性别统计如下如下图所示:
用户年龄分布统计如下图所示:
五、指标统计
- 总共包含多少用户?
userNumber = 6040
- 总共包含多个电影?
movieNumber = 3883
- 平均每个用户对多少部电影进行了评分?
numberIndex = 1000209
avgMovieOfUser = numberIndex/userNumber = 165
- 每部电影 & 每个用户的平均评分是?
用户评分的平均值
用户评分的平均值是<1,4.188679245283019>
用户评分的平均值是<2,3.7131782945736433>
用户评分的平均值是<3,3.9019607843137254>
用户评分的平均值是<4,4.190476190476191>
.....
电影评分的平均值
电影评分的平均值是<2720,2.1662198391420913>
电影评分的平均值是<2722,2.8729096989966556>
电影评分的平均值是<2805,2.8683035714285716>
电影评分的平均值是<2828,2.1074380165289255>
电影评分的平均值是<2761,4.0474777448071215>
.....
参考
《推荐系统开发实践》