1 数据集介绍
采用的数据是来自MovieLen的电影数据集(https://grouplens.org/datasets/movielens)中的MovieLens 1M Dataset。需要的可以在链接中自行下载。
其中有三个dat数据包,分别为:users.dat、ratings.dat、movies.dat。
users.dat:UserID、Gender、Age、Occupation、Zip-code
movies.dat:MovieID、Title、Genres
ratings.dat:UserID、MovieID、Rating、Timestamp
注:dat文件是数据存储的一种格式,即Data缩写。在pandas中用read_table即可打开。
2 具体分析过程
2.1 导入数据
查看movies前5行数据
In [1]: import pandas as pd
...:
...: # 导入数据
...: movies = pd.read_table('./ml-1m/movies.dat', header=None, names=['MovieID', 'Title', 'Genres'], sep='::')
...: ratings = pd.read_table('./ml-1m/ratings.dat', header=None, names=['UserID', 'MovieID', 'Rating', 'Timestam
...: p'], sep='::')
...: users = pd.read_table('./ml-1m/users.dat', header=None, names=['UserID', 'Gender', 'Age', 'Occupation', 'Zi
...: p-code'], sep='::')
D:\Python\Python36\Scripts\ipython:4: ParserWarning: Falling back to the 'python' engine because the 'c' engine does
not support regex separators (separators > 1 char and different from '\s+' are interpreted as regex); you can avoid
this warning by specifying engine='python'.
D:\Python\Python36\Scripts\ipython:5: ParserWarning: Falling back to the 'python' engine because the 'c' engine does
not support regex separators (separators > 1 char and different from '\s+' are interpreted as regex); you can avoid
this warning by specifying engine='python'.
D:\Python\Python36\Scripts\ipython:6: ParserWarning: Falling back to the 'python' engine because the 'c' engine does
not support regex separators (separators > 1 char and different from '\s+' are interpreted as regex); you can avoid
this warning by specifying engine='python'.
In [2]: # 查看movies前5行数据
...: movies.head()
Out[2]:
MovieID Title Genres
0 1 Toy Story (1995) Animation|Children's|Comedy
1 2 Jumanji (1995) Adventure|Children's|Fantasy
2 3 Grumpier Old Men (1995) Comedy|Romance
3 4 Waiting to Exhale (1995) Comedy|Drama
4 5 Father of the Bride Part II (1995) Comedy
In [3]: # 查看ratings前5行数据
...: ratings.head()
Out[3]:
UserID MovieID Rating 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
In [4]: # 查看users前5行数据
...: users.head()
Out[4]:
UserID Gender Age Occupation Zip-code
0 1 F 1 10 48067
1 2 M 56 16 70072
2 3 M 25 15 55117
3 4 M 45 7 02460
4 5 M 25 20 55455
2.2 数据合并
在数据分析中,将不同的表合并起来汇聚成一张总表,会更加便于我们后面的处理与分析。
In [5]: # 数据合并(默认内连接)
...: data = pd.merge(pd.merge(users, ratings), movies)
In [6]: data.head()
Out[6]:
UserID Gender Age Occupation Zip-code MovieID Rating Timestamp \
0 1 F 1 10 48067 1193 5 978300760
1 2 M 56 16 70072 1193 5 978298413
2 12 M 25 12 32793 1193 4 978220179
3 15 M 25 7 22903 1193 4 978199279
4 17 M 50 1 95350 1193 5 978158471
Title Genres
0 One Flew Over the Cuckoo's Nest (1975) Drama
1 One Flew Over the Cuckoo's Nest (1975) Drama
2 One Flew Over the Cuckoo's Nest (1975) Drama
3 One Flew Over the Cuckoo's Nest (1975) Drama
4 One Flew Over the Cuckoo's Nest (1975) Drama
2.3 数据访问
打印出数据表中UserID为1的用户所有的相关数据信息。
In [7]: # 查看数据表中UserID为1的用户所有的相关数据信息
...: data[data.UserID == 1].head()
Out[7]:
UserID Gender Age Occupation Zip-code MovieID Rating Timestamp \
0 1 F 1 10 48067 1193 5 978300760
1725 1 F 1 10 48067 661 3 978302109
2250 1 F 1 10 48067 914 3 978301968
2886 1 F 1 10 48067 3408 4 978300275
4201 1 F 1 10 48067 2355 5 978824291
Title Genres
0 One Flew Over the Cuckoo's Nest (1975) Drama
1725 James and the Giant Peach (1996) Animation|Children's|Musical
2250 My Fair Lady (1964) Musical|Romance
2886 Erin Brockovich (2000) Drama
4201 Bug's Life, A (1998) Animation|Children's|Comedy
2.4 不同性别对电影的平均评分
采用数据透视,建立以Title为行索引,Gerder为列索引,mean为聚合方法来显示Rating中的数据。这样就获得了一张我们自创的data_gender数据表:
In [8]: # 采用数据透视,建立以Title为行索引,Gerder为列索引,mean为聚合方法来显示Rating中的数据。
...: data_gender = data.pivot_table(values='Rating', index='Title', columns='Gender', aggfunc='mean')
...: data_gender.head()
Out[8]:
Gender F M
Title
$1,000,000 Duck (1971) 3.375000 2.761905
'Night Mother (1986) 3.388889 3.352941
'Til There Was You (1997) 2.675676 2.733333
'burbs, The (1989) 2.793478 2.962085
...And Justice for All (1979) 3.828571 3.689024
向data_gender数据表中新插入了一列difference,用来存放男女用户评分的差值。
接下来我们对difference列降序排列(或者升序),即可看到不同性别用户对相同电影评分差异最大的电影了。
In [9]: # 向data_gender数据表中新插入了一列difference,用来存放男女用户评分的差值
...: data_gender['difference'] = data_gender.F - data_gender.M
...: # 对difference列降序排列(或者升序),即可看到不同性别用户对相同电影评分差异最大的电影了
...: data_gender_sorted = data_gender.sort_values(by='difference', ascending=False)
...: data_gender_sorted.head()
Out[9]:
Gender F M \
Title
James Dean Story, The (1957) 4.000000 1.000000
Spiders, The (Die Spinnen, 1. Teil: Der Goldene... 4.000000 1.000000
Country Life (1994) 5.000000 2.000000
Babyfever (1994) 3.666667 1.000000
Woman of Paris, A (1923) 5.000000 2.428571
Gender difference
Title
James Dean Story, The (1957) 3.000000
Spiders, The (Die Spinnen, 1. Teil: Der Goldene... 3.000000
Country Life (1994) 3.000000
Babyfever (1994) 2.666667
Woman of Paris, A (1923) 2.571429
2.5 平均分较高的电影
依然是利用数据透视,对数据进行重新划分后排序,只是此次不再指定列标签,pandas会自动用Rating作为列标签。
In [10]: # 利用数据透视,对数据进行重新划分后排序,只是此次不再指定列标签,pandas会自动用Rating作为列标签
...: data_mean_rating = data.pivot_table(values='Rating', index='Title', aggfunc='mean')
...: data_mean_rating.head()
Out[10]:
Rating
Title
$1,000,000 Duck (1971) 3.027027
'Night Mother (1986) 3.371429
'Til There Was You (1997) 2.692308
'burbs, The (1989) 2.910891
...And Justice for All (1979) 3.713568
随后对数据再进行排序,即可得到平均分较高的电影了,也就是好电影咯!!
In [11]: # 对数据再进行排序,即可得到平均分较高的电影了
...: data_mean_rating_sorted = data_mean_rating.sort_values(by='Rating', ascending=False)
...: data_mean_rating_sorted.head()
Out[11]:
Rating
Title
Ulysses (Ulisse) (1954) 5.0
Lured (1947) 5.0
Follow the Bitch (1998) 5.0
Bittersweet Motel (2000) 5.0
Song of Freedom (1936) 5.0
2.6 评分次数最多热门的电影
利用数据分组操作对Title进行分组,并用size()聚合函数即可统计出每个Title出现的次数,即评分次数。
In [12]: # 利用数据分组操作对Title进行分组,并用size()聚合函数即可统计出每个Title出现的次数,即评分次数
...: data_rating_num = data.groupby('Title').size()
...: data_rating_num.head()
Out[12]:
Title
$1,000,000 Duck (1971) 37
'Night Mother (1986) 70
'Til There Was You (1997) 52
'burbs, The (1989) 303
...And Justice for All (1979) 199
dtype: int64
再利用排序方法对值进行降序排列,即可获得热门电影的数据表啦!
In [13]: # 利用排序方法对值进行降序排列,即可获得热门电影的数据表
...: data_rating_num_sorted = data_rating_num.sort_values(ascending=False)
...: data_rating_num_sorted.head()
Out[13]:
Title
American Beauty (1999) 3428
Star Wars: Episode IV - A New Hope (1977) 2991
Star Wars: Episode V - The Empire Strikes Back (1980) 2990
Star Wars: Episode VI - Return of the Jedi (1983) 2883
Jurassic Park (1993) 2672
dtype: int64
2.7 问题出现在哪里????
推荐大家按照我上面的步骤,去体验一下数据分析带给我们的快乐!!如果你做了,你就会发现一个很奇怪的问题!
这个问题在上面第五项分析中最为明显:为什么那些平均分高的电影,我从来没看过?甚至有些听都没听过呢?这个问题
是不符合常理的,毕竟国内外好电影大家按说都应该耳熟能详的,所以这其中一定存在错误。
这个问题就在于:有些电影只有极少数的人(1-2人)看过,并且觉得很好看,给了很高的评分,这个时候我们去分析数据的时候,得到的就是这种极小众认为好看的电影。因此,我们应该对评分次数做出最小值限定,使数据更加合理:
加入评分次数限制的分析不同性别对电影的平均评分:
In [14]: # 加入评分次数限制后,分析不同性别对电影的平均评分
...: data_gender_hot = data_gender.loc[data_rating_num[data_rating_num > 1000].index]
...: data_gender_hot.head()
Out[14]:
Gender F M difference
Title
2001: A Space Odyssey (1968) 3.825581 4.129738 -0.304156
Abyss, The (1989) 3.659236 3.689507 -0.030272
African Queen, The (1951) 4.324232 4.223822 0.100410
Air Force One (1997) 3.699588 3.555822 0.143766
Airplane! (1980) 3.656566 4.064419 -0.407854
In [15]: # 对数据再进行排序
...: data_gender_hot_sorted = data_gender_hot.sort_values(by='difference', ascending=False)
...: data_gender_hot_sorted.head()
Out[15]:
Gender F M difference
Title
Rocky Horror Picture Show, The (1975) 3.673016 3.160131 0.512885
Mary Poppins (1964) 4.197740 3.730594 0.467147
Gone with the Wind (1939) 4.269841 3.829371 0.440471
Full Monty, The (1997) 4.113456 3.760976 0.352481
Little Mermaid, The (1989) 3.975936 3.632375 0.343561
加入评分次数限制的分析平均分高的电影:
In [16]: # 加入评分次数限制的分析平均分高的电影
...: data_mean_rating_number = data_mean_rating.loc[data_rating_num[data_rating_num > 1000].index]
...: data_mean_rating_number_sorted = data_mean_rating_number.sort_values(by='Rating', ascending=False)
...: data_mean_rating_number_sorted.head()
Out[16]:
Rating
Title
Shawshank Redemption, The (1994) 4.554558
Godfather, The (1972) 4.524966
Usual Suspects, The (1995) 4.517106
Schindler's List (1993) 4.510417
Raiders of the Lost Ark (1981) 4.477725
3 代码汇总
注:上面代码为了方便输出均采用输出数据前5行(.head())
import pandas as pd
# 导入数据
movies = pd.read_table('./ml-1m/movies.dat', header=None, names=['MovieID', 'Title', 'Genres'], sep='::')
ratings = pd.read_table('./ml-1m/ratings.dat', header=None, names=['UserID', 'MovieID', 'Rating', 'Timestamp'], sep='::')
users = pd.read_table('./ml-1m/users.dat', header=None, names=['UserID', 'Gender', 'Age', 'Occupation', 'Zip-code'], sep='::')
# 查看数据
print("查看movies数据")
print(movies)
print("查看ratings数据")
print(ratings)
print("查看users数据")
print(users)
# 数据合并(默认内连接)
data = pd.merge(pd.merge(users, ratings), movies)
print("查看合并后的数据")
print(data)
# 查看数据表中UserID为1的用户所有的相关数据信息
print("查看数据表中UserID为1的用户所有的相关数据信息")
print(data[data.UserID == 1])
# 采用数据透视,建立以Title为行索引,Gerder为列索引,mean为聚合方法来显示Rating中的数据。
data_gender = data.pivot_table(values='Rating', index='Title', columns='Gender', aggfunc='mean')
print("不同性别对电影的平均评分表")
print(data_gender)
# 向data_gender数据表中新插入了一列difference,用来存放男女用户评分的差值
data_gender['difference'] = data_gender.F - data_gender.M
# 对difference列降序排列(或者升序),即可看到不同性别用户对相同电影评分差异最大的电影了
data_gender_sorted = data_gender.sort_values(by='difference', ascending=False)
print("不同性别对电影的平均评分表(difference)")
print(data_gender_sorted)
# 利用数据透视,对数据进行重新划分后排序,只是此次不再指定列标签,pandas会自动用Rating作为列标签
data_mean_rating = data.pivot_table(values='Rating', index='Title', aggfunc='mean')
# 对数据再进行排序,即可得到平均分较高的电影了
data_mean_rating_sorted = data_mean_rating.sort_values(by='Rating', ascending=False)
print("平均分较高的电影数据表")
print(data_mean_rating_sorted)
# 利用数据分组操作对Title进行分组,并用size()聚合函数即可统计出每个Title出现的次数,即评分次数
data_rating_num = data.groupby('Title').size()
# 利用排序方法对值进行降序排列,即可获得热门电影的数据表
data_rating_num_sorted = data_rating_num.sort_values(ascending=False)
print("热门电影的数据表")
print(data_rating_num_sorted)
# 加入评分次数限制后,分析不同性别对电影的平均评分
data_gender_hot = data_gender.loc[data_rating_num[data_rating_num > 1000].index]
# 对数据再进行排序
data_gender_hot_sorted = data_gender_hot.sort_values(by='difference', ascending=False)
print("同性别对电影的平均评分")
print(data_gender_hot_sorted)
# 加入评分次数限制的分析平均分高的电影
data_mean_rating_number = data_mean_rating.loc[data_rating_num[data_rating_num > 1000].index]
data_mean_rating_number_sorted = data_mean_rating_number.sort_values(by='Rating', ascending=False)
print("加入评分次数限制的分析平均分高的电影")
print(data_mean_rating_number_sorted)
4 总结
在数据处理过程中,合并、透视、分组、排序这四大类操作是最经常用的,所以希望大家能够熟练掌握这四种方法的用法。
有问题想与我交流的直接留言即可咯! 拜了个拜~!