Python大数据分析9:案例-电影评分数据集的分析2

在进行数据分析的时候,除了我们要掌握必要的方法外,在很多时候我们还要清楚的了解数据可能存在的问题。比如这个平均值没有考虑到评分者的数量,退一步说,一个广受评价的电影居然始终是满分5分,难道不可疑吗?有没有一种情况,只有一位观众对这部电影打分,如果是5分,则这部电影平均评分就是5分。显然这是有问题的。

为此,我们改进了方法,不仅要考虑平均分,还要考虑评分的人数。为了实现对结果同时进行两种不同的聚合运算,我们可以使用agg方法来集成:

print(frame[‘rating’].groupby([frame[‘gender’], frame[‘title’]]).agg([‘mean’, ‘count’]))

这里的agg方法是DataFrame提供的方法,它可以将多个不同的聚合函数一起进行计算。

然而此时的结果没有排序,并不能有效的看出最有价值的数据。

为此,我们再次排序,那么是应该先进行以个数为依据的排序呢,还是以平均评分为依据呢?不妨,我们先按照个数来排,个数相同的再按照平均评分来排:

pd.set_option(‘display.max_rows’, None)

print(frame[‘rating’].groupby([frame[‘gender’], frame[‘title’]]).agg([‘mean’, ‘count’]).

      sort_values(by=[‘count’, ‘mean’], ascending=[False, False]))

此时代码比较长,我们进行了换行分隔,其实是一条语句。从中我们果然发现刚才有些电影虽然是平均5分,但是其实评分观众很少,实际意义并不大,比如这个Star Kid(1997)。

为此,我们再次调整次序,先按照平均评分再按照个数:

print(frame[‘rating’].groupby([frame[‘gender’], frame[‘title’]]).agg([‘mean’, ‘count’]).

      sort_values(by=[‘mean’, ‘count’], ascending=[False, False]))

请注意,为了看清全部结果,我们增加设置显示了全部记录。此时的结果比较有意义,可以看出男性观众最喜爱看的电影确实是一些经典影片,而且平均评分相对较高,评分数量也较多。

而女性观众显然和男性观众的差异性很明显。但是这种分析依然显得结果比较乱,因为最高分往往并不在前面,如这个排在女性观众第一位的电影之所以排在第一位完全是因为它有最高的评分数量。

因此我们再次进行了调整,这次我们首先保存了进行两种聚合运算结果的新DataFrame:

frame1 = frame[‘rating’].groupby([frame[‘gender’], frame[‘title’]]).agg([‘mean’, ‘count’])

print(frame1)

然后对于这个结果我们进行必要的过滤和排序,比如首先过滤到全部的评分次数小于100的电影,然后只需按照平均评分排序即可:

frame1 = frame[‘rating’].groupby([frame[‘gender’], frame[‘title’]]).agg([‘mean’, ‘count’])

print(frame1[frame1[‘count’] > 100].sort_values(by=’mean’, ascending=False))

明显看出排在前面的记录,都是一些高分电影。

并且也容易看出女性观众最喜欢的电影情况,显然这种分析更为合理。因此在很多时候,我们需要综合利用各种方法来比较分析结果,找到更为适合和更能展示效果的分析结论。

当然,分组并不是唯一解决此类问题的方法。我们也可以使用一些其他的方法来实现,比如透视图。所谓透视图,可以理解为一个多维矩阵,过去按照几个列来分组,现在就可以按照几个列来展示,比如我们还是以性别和电影来分析,看看按性别来计算每部电影的平均得分。此时,就以分别将性别和电影标题分别设置为行和列或者列和行。考虑到电影很多,更适合作为行的内容,因此设置为:

print(frame.pivot_table(‘rating’, index=’title’, columns=’gender’, aggfunc=’mean’))

其中index表示行为电影标题,列表示性别,每个矩阵单元格显示的是评分的平均值,这个依赖于第一个参数指定的评分字段和最后一个参数指定的聚合方法。

此时按照电影标题排序的结果意义不是很大,可以进一步调整结果的次序,比如按照女性观众的平均得分重新调整:

print(frame.pivot_table(‘rating’, index=’title’, columns=’gender’, aggfunc=’mean’).

      sort_values(by=’F’, ascending=False))

此时的结果更为明确些,可以更容易看到有价值的数据。

但是依然也会遇到刚才同样的问题,有些电影评分数量不足,却具有较高的平均评分。为此我们也可以进行必要的过滤。

首先我们先得到一个每部电影评分数量的汇总信息,这次我们使用了分组:

ratings_by_title = frame.groupby(‘title’).size()

print(ratings_by_title)

其中的size返回每组的个数,相当于count,只是不区分多个不同的列,只显示一个总数。

可以进一步选择其中总数大于100的记录:

print(ratings_by_title.index[ratings_by_title > 100])

由于此时这个结果只有一列,是个序列类型的变量,因此可以直接使用序列变量的名称作为具体数值列的表示,选择数值范围内的记录。

此时,这些电影都满足至少100个评分以上。

然后把这个范围内的电影标题作为选择条件,在当前排好序的透视图中过滤,其实就是按照透视图的索引来过滤,只显示符合loc方法参数中电影范围内的所有电影元素。

print(frame.pivot_table(‘rating’, index=’title’, columns=’gender’, aggfunc=’mean’).

      loc[ratings_by_title.index[ratings_by_title > 100]])

甚至可以再次排序:

print(frame.pivot_table(‘rating’, index=’title’, columns=’gender’, aggfunc=’mean’).

      loc[ratings_by_title.index[ratings_by_title > 100]].

      sort_values(by=’F’, ascending=False))

虽然有点复杂了,但是所有的过程,其实就是一个组合应用的过程。大家多练习才能更好的掌握。

到此为止,我们已经尝试了多种分析性别和观影喜好的关系,并且注意到不同性别对于电影的评价等级差异很明显,那么究竟哪些电影的不同性别分歧更大一些呢?

在数据透视表的基础上,我们可以很容易进行分析。首先为了方便处理,我们将当前透视表保存下来:

frame1 = frame.pivot_table(‘rating’, index=’title’, columns=’gender’, aggfunc=’mean’)

print(frame1)

我们可以发现,此时的男女两列数值对比很明显。

为此,我们增加一个计算列:

frame1[‘diff’] = frame1[‘M’] – frame1[‘F’]

print(frame1)

这是我们为什么要保存下这个数据透视表的原因,后续可以对它进行修改。其中的diff就是差值。

接下来只需按照diff降序排序即可看到评分分歧最大的电影:

print(frame1.sort_values(by=’diff’, ascending=False))

当然细心的同学可以也得到,如果按照升序来排,这种排序最大值和最小值都是分歧大的表现,只是男女比较时谁先谁后的问题。

print(frame1.sort_values(by=’diff’, ascending=True))

因此更为合理的设计应该是计算差值的绝对值,这一次我们再次使用了apply方法,应用了绝对值处理。

frame1[‘diff’] = (frame1[‘M’] – frame1[‘F’]).apply(abs)

这个练习也充分展示了透视表的强大之处,换成一般分分组来处理并不容易进行,因为分组通常是将所有的分组都作为行的索引,不同行之间的比较并不容易,相反,借助于透视表,我们可以将所有的信息灵活的放置在列中,从而方便实现一些特殊功能。

当然,利用评价平均分的差值来计算差异度,其实并不十分科学,最为有效的方法还是应该考虑使用标准差之类的方法。

print(frame[‘rating’].groupby([frame[‘gender’], frame[‘title’]]).std().sort_values(ascending=False))

比如这里我们按照性别和电影标题分组,计算每组的标准差,并按照降序排序,可以看到不同性别下哪些电影评分的差异度更为明显。

发表评论

邮箱地址不会被公开。 必填项已用*标注