可视化
表格是组织和可视化数据的有力方式。然而,无论组织得多么好,大型数字表格可能难以解读。有时,解读图形比解读数字容易得多。
在本章中,我们将学习数据分析的一些基本图形方法。我们的数据来源是 Internet Movie Database,这是一个包含电影、电视节目、视频游戏等信息的在线数据库。Box Office Mojo 网站提供了IMDB数据的许多摘要,我们改编了其中的一部分。我们还使用了 The Numbers 的数据摘要,该网站的标语是“数据与电影业务交汇之处”。
from datascience import *
import matplotlib
path_data = '../../assets/data/'
matplotlib.use('Agg')
%matplotlib inline
import matplotlib.pyplot as plots
from matplotlib.ticker import MaxNLocator
plots.style.use('fivethirtyeight')
import numpy as np
np.set_printoptions(threshold=50)
散点图和折线图
表格 actors 包含好莱坞男女演员的数据。各列如下:
| 列名 | 内容 |
|---|---|
Actor |
演员姓名 |
Total Gross |
该演员所有电影的国内票房总收入,单位百万美元 |
Number of Movies |
该演员出演的电影数量 |
Average per Movie |
总收入除以电影数量 |
#1 Movie |
该演员出演的最卖座电影 |
Gross |
该演员的 #1 Movie 的国内票房收入,单位百万美元 |
在计算票房收入时,数据编制者没有包含演员仅客串或出演但屏幕时间不多的电影。
该表有50行,对应50位最卖座演员。该表已按 Total Gross 排序,因此很容易看出哈里森·福特(Harrison Ford)是票房最高的演员。在该表创建时,他的电影在国内票房上获得的收入超过了表中任何其他演员的电影。
actors = Table.read_table(path_data + 'actors.csv')
actors
Actor | Total Gross | Number of Movies | Average per Movie | #1 Movie | Gross
Harrison Ford | 4871.7 | 41 | 118.8 | Star Wars: The Force Awakens | 936.7
Samuel L. Jackson | 4772.8 | 69 | 69.2 | The Avengers | 623.4
Morgan Freeman | 4468.3 | 61 | 73.3 | The Dark Knight | 534.9
Tom Hanks | 4340.8 | 44 | 98.7 | Toy Story 3 | 415
Robert Downey, Jr. | 3947.3 | 53 | 74.5 | The Avengers | 623.4
Eddie Murphy | 3810.4 | 38 | 100.3 | Shrek 2 | 441.2
Tom Cruise | 3587.2 | 36 | 99.6 | War of the Worlds | 234.3
Johnny Depp | 3368.6 | 45 | 74.9 | Dead Man's Chest | 423.3
Michael Caine | 3351.5 | 58 | 57.8 | The Dark Knight | 534.9
Scarlett Johansson | 3341.2 | 37 | 90.3 | The Avengers | 623.4
... (40 rows omitted)术语。 “变量”是我们一直称之为“特征”或“属性”(如“电影数量”)的正式名称。术语“变量”强调了特征对于不同个体可以具有不同取值这一点。例如,演员出演的电影数量因演员而异。
具有数值且可以数值方式测量的变量,如“电影数量”或“每部电影的平均票房收入”,被称为“定量”或“数值”变量。
散点图
“散点图”展示两个数值变量之间的关系。在早期章节中,你看到了一个散点图的示例,我们考察了两部经典小说中的句号数量和字符数量。
Table 方法 scatter 绘制一个散点图,每个点对应表格中的一行。它的第一个参数是要绘制在水平轴上的列标签,第二个参数是垂直轴上的列标签。
actors.scatter('Number of Movies', 'Total Gross')
A scatter plot shows the relationship between the 'Number of Movies' (x-axis) and 'Total Gross' (y-axis). Most of the blue data points are concentrated between 20 to 50 movies and a gross of 2500 to 3500. A few notable outliers exist higher up on the y-axis, reaching peaks near 4900 and 4750 gross.该图包含50个点,每个点对应表中的一位演员。你可以看到它总体向上倾斜。一般来说,演员出演的电影越多,所有这些电影的总票房就越高。
正式地说,我们说该图显示了变量之间的“关联”,并且这种关联是“正”的:一个变量的高值倾向于与另一个变量的高值相关联,一个变量的低值倾向于与另一个变量的低值相关联。
当然存在一些变异性。有些演员出演了很多电影但总票房一般。另一些演员出演的电影数量一般但总票房很高。关联为正只是对广泛总体趋势的一种陈述。
在本课程的后面部分,我们将学习如何量化关联。目前,我们只需进行定性思考。
既然我们已经探讨了电影数量与“总”票房收入的关系,让我们将注意力转向它与“平均”每部电影票房收入的关系。
actors.scatter('Number of Movies', 'Average per Movie')
A scatter plot shows the relationship between the 'Number of Movies' (x-axis) and 'Average per Movie' (y-axis). All of the blue data points are below 200 for the average per Movie with a negative relationship where when the average decreases, so does the number. There is one outlier with a small number of movies (less than 20) but a high average over 400.这是一幅明显不同的图,显示了一种“负”关联。一般来说,演员出演的电影越多,每部电影的平均票房收入就越“低”。
此外,其中一个点相当高,且位于图的左侧。它对应一位电影数量较少但平均每部电影票房很高的演员。这个点是一个“异常值”。它位于数据的一般范围之外。实际上,它离图中所有其他点都很远。
我们将通过查看图左右两端的点来进一步检查负关联。
对于右端,让我们放大图的主体部分,只查看没有异常值的部分。
no_outlier = actors.where('Number of Movies', are.above(10))
no_outlier.scatter('Number of Movies', 'Average per Movie')
A scatter plot with most of the data from the previous scatter plot is shown with the outlier removed so the y-axis now ends just above 160. The negative relationship between number and average is shown more clearly.负关联仍然清晰可见。让我们找出对应于图右侧电影数量较大的点的演员:
actors.where('Number of Movies', are.above(60))
Actor | Total Gross | Number of Movies | Average per Movie | #1 Movie | Gross
Samuel L. Jackson | 4772.8 | 69 | 69.2 | The Avengers | 623.4
Morgan Freeman | 4468.3 | 61 | 73.3 | The Dark Knight | 534.9
Robert DeNiro | 3081.3 | 79 | 39 | Meet the Fockers | 279.3
Liam Neeson | 2942.7 | 63 | 46.7 | The Phantom Menace | 474.5伟大的演员罗伯特·德尼罗(Robert DeNiro)拥有最高的电影数量和最低的平均每部电影票房收入。其他优秀演员的点离得并不很远,但德尼罗的点处于极端位置。
要理解负关联,请注意演员出演的电影越多,这些电影在风格、流派和票房吸引力方面可能就越多样化。例如,一个演员可能出演一些高票房的动作片或喜剧片(如《拜见岳父大人》),同时也出演大量可能很优秀但不吸引大量观众的小众电影。因此,该演员的平均每部电影票房收入可能相对较低。
为了从不同的角度探讨这个论点,现在让我们看看这个异常值。
actors.where('Number of Movies', are.below(10))
Actor | Total Gross | Number of Movies | Average per Movie | #1 Movie | Gross
Anthony Daniels | 3162.9 | 7 | 451.8 | Star Wars: The Force Awakens | 936.7作为一名演员,安东尼·丹尼尔斯(Anthony Daniels)可能没有罗伯特·德尼罗(Robert DeNiro)那样的地位。但他的7部电影平均每部票房收入高达近4.52亿美元,令人震惊。
这些电影是什么?你可能知道《星球大战》中的机器人 C-3PO:

那就是金属服装里的 Anthony Daniels。他扮演了 C-3PO。
丹尼尔斯先生的全部电影作品(除了客串)都是高票房的《星球大战》系列电影。这既解释了他的高平均票房收入,也解释了他电影数量少的原因。
流派和制作预算等变量对电影数量与平均每部电影票房收入之间的关联有影响。这个例子提醒我们,研究两个变量之间的关联通常也需要理解其他相关变量。
折线图
折线图有时也称为线图,是最常见的可视化方式之一。它们通常用于研究时间趋势和模式。
表格 movies_by_year 包含1980年至2015年间美国工作室每年制作的电影数据。各列如下:
| 列名 | 内容 |
|---|---|
Year |
年份 |
Total Gross |
所有发行电影的国内总票房,单位百万美元 |
Number of Movies |
发行电影的数量 |
#1 Movie |
最卖座电影 |
movies_by_year = Table.read_table(path_data + 'movies_by_year.csv')
movies_by_year
Year | Total Gross | Number of Movies | #1 Movie
2015 | 11128.5 | 702 | Star Wars: The Force Awakens
2014 | 10360.8 | 702 | American Sniper
2013 | 10923.6 | 688 | Catching Fire
2012 | 10837.4 | 667 | The Avengers
2011 | 10174.3 | 602 | Harry Potter / Deathly Hallows (P2)
2010 | 10565.6 | 536 | Toy Story 3
2009 | 10595.5 | 521 | Avatar
2008 | 9630.7 | 608 | The Dark Knight
2007 | 9663.8 | 631 | Spider-Man 3
2006 | 9209.5 | 608 | Dead Man's Chest
... (26 rows omitted)Table 方法 plot 生成一个折线图。它的两个参数与 scatter 相同:首先是水平轴上的列,然后是垂直轴上的列。以下是1980年至2015年间每年发行电影数量的折线图。
movies_by_year.plot('Year', 'Number of Movies')
A line graph tracks the 'Number of Movies' on the y-axis over time from 1980 to 2015 on the x-axis. The blue line shows an overall upward trend, starting below 200 movies in 1980, experiencing several cyclical peaks and valleys over the decades, and eventually beginning to plateau at a peak of 700 movies around 2014. Notable sharp declines occur around 1990, 1995, and 2009 before recovering to higher numbers. There is also a large jump from below 200 movies in 1980 to above 500 in 1984.该图急剧上升,然后呈现缓慢上升趋势,尽管数字每年都有显著变化。1980年代初的急剧上升部分是由于工作室在经历了1970年代电影制作人驱动的几年后重新回到电影制作的前沿。
我们的重点将放在更近的年份。为了与电影主题保持一致,对应2000年至2015年的行的表格已被赋名为 century_21。
century_21 = movies_by_year.where('Year', are.above(1999))
century_21.plot('Year', 'Number of Movies')
# Ensure the plot only shows integers
plots.gca().xaxis.set_major_locator(MaxNLocator(integer=True))
A line graph tracks the 'Number of Movies' on the y-axis over time from 2000 to 2015 on the x-axis. The blue line illustrates a general upward trajectory, rising from just under 500 movies in 2000 to a plateau of approximately 700 movies by 2014. This growth includes a prominent peak near 630 movies in 2007 followed by a sharp decline to around 520 movies in 2009 before sharply rebounding.2008年的全球金融危机产生了明显的影响——2009年发行的电影数量急剧下降。
然而,票房金额并没有受到太大影响。
century_21.plot('Year', 'Total Gross')
# Ensure the plot only shows integers
plots.gca().xaxis.set_major_locator(MaxNLocator(integer=True))
A line graph shows the 'Total Gross' on the y-axis over time from 2000 to 2015 on the x-axis. The blue line depicts a steady upward trend overall, climbing from a low of roughly 7600 in 2000 to a peak exceeding 11000 by 2015. Along this growth trajectory, temporary declines occur around 2005, 2011, and 2014 before the graph quickly rebounds.2009年的国内总票房高于2008年,尽管存在金融危机且发行的电影数量少得多。
这个看似矛盾的一个原因是,经济衰退时人们倾向于去看电影。《纽约时报》在2009年2月报道称“经济低迷时期,美国人涌向电影院”。文章引用南加州大学的马丁·卡普兰(Martin Kaplan)的话说:“人们想要忘记烦恼,他们想和其他人在一起。”当假期和昂贵的娱乐活动变得负担不起时,电影提供了受欢迎的娱乐和慰藉。
2009年票房收入高的另一个原因是电影《阿凡达》及其3D版本。不仅《阿凡达》是2009年最卖座的电影,而且根据某些计算,它也是有史以来票房最高的电影之一,我们稍后会看到。
century_21.where('Year', are.equal_to(2009))
Year | Total Gross | Number of Movies | #1 Movie
2009 | 10595.5 | 521 | Avatar