Python大数据分析8:案例-电影评分数据集的分析1

这次我们准备结合一个著名的电影评价数据集合来检验下我们前段时间学习的数据分析方法。

这个数据集合可以免费的从官网上获取,主要提供了观众对电影的评价数据,其中还对观众和电影给出了较为完整的属性描述。其中主页的下部有一个older datasets,其中就有一个100K的数据集,直接点击即可下载。我们下载后解压后可以看到很多文件,我们只需使用其中的三个文件,分别是观众数据u.user、电影数据u.item、和评分数据u.data。

其中的u.user为观众数据,共有943个观众记录,分别记录了观众ID、年龄、性别、职业和邮编,此处为美国五位邮编号码,通过竖线分隔。

u.item为电影数据,共有1682部电影,每部电影都提供了电影ID、名称、拍摄时间、上映时间、网址,后面19个一零列表示19种电影类别,具体情况大家可以参见README文档中的说明,如果为1表示属于该类别。

u.data为评分数据,共有10万个记录,这也是为什么称为100K的原因。其中给出了观众ID、电影ID、评分数据和评分时间。其中的评分数据为五级评分,5表示最喜欢,1表示最不喜欢,时间类型需要转换后才能正确显示,这些以后学习了时间序列分析后再做说明。

我们直接通过练习来切入数据分析。

在数据分析的一开始,我们首先需要读取数据。以前我们介绍的都是直接在程序中表达数据集合,如何从数据文件来读取数据并生成DataFrame呢?其实很简单。Pandas的read_table函数就可以直接实现这个效果。

unames = [‘uid’, ‘age’, ‘gender’, ‘occupation’, ‘zip’]

users = pd.read_table(‘c:\\temp\\MovieLens\\u.user’, sep=’|’, header=None, names=unames)

这几个参数含义都比较直观,第一个是数据文件,第二个是一行记录中不同列的分隔符,第三个参数表示第一行是否是行标题,最后一个是映射关系,说明如何将读取的每一行多个列信息映射到DataFrame的数据列中。

为了能看到最终效果,我们可以读取显示下数据效果。请注意,由于真实数据处理往往所涉及的数据量都很大,因此不建议全部读取,常见的方法还是取样读取,比如只读取前5个记录:

print(users.head(5))

当然类似的效果也可以通过切片来实现:

print(users[:5])

接下来,我们读取评分数据,并通过连接和现有观众数据关联起来。

rnames = [‘uid’, ‘mid’, ‘rating’, ‘timestamp’]

ratings = pd.read_table(‘c:\\temp\\MovieLens\\u.data’, sep=’\t’, header=None, names=rnames)

print(ratings[:5])

这里要注意分隔符要根据数据实际情况来定义,一般而言,最好在分析前先将数据读取并显示几条记录,以确定数据读取正常。

我们通过自然连接将两个数据集合关联起来:

frame = pd.merge(ratings, users)

print(frame.head(5))

到此为止,数据准备好了。

对于电影评分,从多种角度我们可以发现很多有趣的现象。比如我们想看看观众的不同性别、年龄对电影的平均评分情况。首先看看性别评分的差异:

print(frame[‘rating’].groupby(frame[‘gender’]).mean())

能看出女性观众比男性观众评分平均值更高些,只是幅度不大。其实这种过于汇总的分析往往很难看出真正的差别。下面我们继续分析。

再看看不同年龄段,我们按照四舍五入的方法将年龄映射为年龄段:

print(frame[‘rating’].groupby(frame[‘age’].apply(round, args=[-1])).mean())

-1的round参数表示四舍五入到十位。

看得出,随着年龄的增加,电影平均评分似乎呈现不断上升的趋势,但是达到60岁左右达到最高峰。

然后结合年龄段和性别,看看情况究竟是什么情况。

print(frame[‘rating’].groupby([frame[‘age’].apply(round, args=[-1]), frame[‘gender’]]).mean())

从结果看的出来,在不同年龄段,男性女性观众的评分差异非常明显。比如在30岁左右,男女评分的区别其实并不明显,而在70岁这个年龄段,可以看出,女性评分似乎更为苛刻些,与男性评分的差距最大。而反过来,在40岁年龄段,女性又比男性宽容,虽然这个差距远远小于70岁的情况。这些有趣的分析结果在一定程度可以揭示出观众不同性别在不同年龄段的兴趣差异。

下面我们继续增加数据,将电影也关联进来。这里有两个主要问题:一是读取电影数据,这个数据读取并不容易,首先是列很多,因此需要结合说明文档仔细定义列的名称:

mnames = [‘mid’, ‘title’, ‘date1’, ‘date2’, ‘url’,

          ‘unknown’, ‘Action’, ‘Adventure’, ‘Animation’,

          ‘Children’, ‘Comedy’, ‘Crime’, ‘Documentary’, ‘Drama’,

          ‘Fantasy’, ‘Film-Noir’, ‘Horror’, ‘Musical’,

          ‘Mystery’, ‘Romance’, ‘Sci-Fi’, ‘Thriller’, ‘War’, ‘Western’]

movies = pd.read_table(‘c:\\temp\\MovieLens\\u.item’, sep=’|’, header=None, names=mnames)

然而还是出现错误,大致的信息是字符集合转换的问题。

对于此类问题,可以通过指定编码字符集来解决,这里一般需要从两个地方处理:

一是在Python中重新设置字符集,比如在设置中选择编辑器,在文件编码中更换当前默认的GBK为ISO-8859-1。

同时还要考虑在代码中通过encoding指定标准字符集。我们于是输出些结果看看,此时没问题了。

movies = pd.read_table(‘c:\\temp\\MovieLens\\u.item’, sep=’|’, header=None, names=mnames, encoding=’ISO-8859-1′)

print(movies.head(5))

第二,如何对于已经连接起来的两个数据集合再连接一个数据集合呢?其实很简单,再次使用merge即可:

frame = pd.merge(pd.merge(ratings, users), movies)

print(frame.head(5))

此时的输出结果看出来没问题。

这次有了电影详细信息,我们可以继续深入了解评分情况。比如按性别来计算每部电影的平均得分,

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

说明下,我们这里使用电影标题作为分组依据主要是考虑到输出结果的直观,其实真正有效的电影标识列应该是电影ID。

这里不仅做了分组统计,而且还进行按照平均评分的倒序输出。从中可以看出很多打5分的好评情况,如男性观众对“Star Kid(1997)”这部电影排名满分。但是这种数据是真实有效的吗?

发表评论

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