pandas实例 - MovieLens电影数据实战分析

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 总结

在数据处理过程中,合并、透视、分组、排序这四大类操作是最经常用的,所以希望大家能够熟练掌握这四种方法的用法。

有问题想与我交流的直接留言即可咯! 拜了个拜~!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值