变异性

均值告诉我们直方图的平衡位置。但在我们见过的几乎每一个直方图中,值都分布在均值的两侧。它们能离均值多远?为了回答这个问题,我们将开发一个关于均值变异性的度量。

我们首先描述如何计算这个度量,然后看看为什么它是一个值得计算的好度量。

[In ]:
from datascience import *
%matplotlib inline
path_data = '../../../assets/data/'
import matplotlib.pyplot as plots
plots.style.use('fivethirtyeight')
import numpy as np

偏离平均值的粗略大小

为简单起见,我们将从一个仅包含四个值的简单数组 any_numbers 开始计算。正如你将看到的,我们的方法可以轻松扩展到任何其他值的数组。

[In ]:
any_numbers = make_array(1, 2, 2, 10)

目标是粗略衡量数字与其平均值的偏离程度。为此,我们首先需要平均值:

[In ]:
# Step 1. The average.

mean = np.mean(any_numbers)
mean
3.75

接下来,让我们找出每个值距离均值有多远。这些被称为“离差(deviations from the average)”。“离差”就是一个值减去平均值。表格 calculation_steps 显示了结果。

[In ]:
# Step 2. The deviations from average.

deviations = any_numbers - mean
calculation_steps = Table().with_columns(
        'Value', any_numbers,
        'Deviation from Average', deviations
        )
calculation_steps
Value | Deviation from Average
1     | -2.75
2     | -1.75
2     | -1.75
10    | 6.25

一些离差是负的;这些对应低于平均值的值。正离差对应高于平均值的值。

为了粗略计算离差的大小,很自然地会计算离差的均值。但当所有离差加在一起时,有趣的事情发生了:

[In ]:
sum(deviations)
0.0

正离差恰好抵消了负离差。这对于所有数字列表都成立,无论列表的直方图是什么样子:离差之和为零。

因为离差之和为0,离差的均值也为0:

[In ]:
np.mean(deviations)
0.0

因此,离差的均值不是衡量离差大小的有用度量。我们真正想知道的是离差大致有多大,无论它们是正还是负。所以我们需要一种消除离差符号的方法。

有两种久经考验的消除符号的方法:绝对值和平方。事实证明,使用平方可以构建一个具有极其强大性质的度量,其中一些性质我们将在本课程中学习。

因此,让我们通过平方所有离差来消除符号。然后我们取这些平方的均值:

[In ]:
# Step 3. The squared deviations from average

squared_deviations = deviations ** 2
calculation_steps = calculation_steps.with_column(
   'Squared Deviations from Average', squared_deviations
    )
calculation_steps
Value | Deviation from Average | Squared Deviations from Average
1     | -2.75                  | 7.5625
2     | -1.75                  | 3.0625
2     | -1.75                  | 3.0625
10    | 6.25                   | 39.0625
[In ]:
# Step 4. Variance = the mean squared deviation from average

variance = np.mean(squared_deviations)
variance
13.1875

方差: 上面计算的平均平方离差称为值的“方差”(variance)。

虽然方差确实给了我们关于分散程度的概念,但它与原始变量的尺度不同,因为其单位是原始单位的平方。这使得解释非常困难。

因此,我们通过取方差的正平方根回到原始尺度:

[In ]:
# Step 5.
# Standard Deviation:    root mean squared deviation from average
# Steps of calculation:   5    4      3       2             1

sd = variance ** 0.5
sd
3.6314597615834874

标准差

我们刚才计算的量称为列表的“标准差”(standard deviation),缩写为SD。它大致衡量了列表中数字与其平均值的偏离程度。

定义。 列表的SD定义为“离差的均方根”。这听起来有点拗口。但从右往左读,你就得到了计算中的步骤顺序。

计算。 上述五个步骤得出SD。你也可以使用函数 np.std 计算数组中值的SD:

[In ]:
np.std(any_numbers)
3.6314597615834874

使用SD

为了了解我们能从SD中学到什么,让我们转向比 any_numbers 更有趣的数据集。表格 nba13 包含2013年美国国家篮球协会(NBA)球员的数据。对于每位球员,表格记录了他通常打的位置、身高(英寸)、体重(磅)和年龄(岁)。

[In ]:
nba13 = Table.read_table(path_data + 'nba2013.csv')
nba13
Name            | Position | Height | Weight | Age in 2013
DeQuan Jones    | Guard    | 80     | 221    | 23
Darius Miller   | Guard    | 80     | 235    | 23
Trevor Ariza    | Guard    | 80     | 210    | 28
James Jones     | Guard    | 80     | 215    | 32
Wesley Johnson  | Guard    | 79     | 215    | 26
Klay Thompson   | Guard    | 79     | 205    | 23
Thabo Sefolosha | Guard    | 79     | 215    | 29
Chase Budinger  | Guard    | 79     | 218    | 25
Kevin Martin    | Guard    | 79     | 185    | 30
Evan Fournier   | Guard    | 79     | 206    | 20
... (495 rows omitted)

以下是球员身高的直方图。

[In ]:
nba13.select('Height').hist(bins=np.arange(68, 88, 1))
Histogram with 'Height' on the x-axis and 'Percent per unit' on the y-axis. The height of the bars is generally increasing from about x=70 to x=82. After that, the height of the bars decrease until about x=86.

不出所料,NBA球员都很高!他们的平均身高略高于79英寸(6'7"),比美国男性的平均身高高出约10英寸。

[In ]:
mean_height = np.mean(nba13.column('Height'))
mean_height
79.06534653465347

球员身高与平均值大约相差多少?这是由身高的SD衡量的,约为3.45英寸。

[In ]:
sd_height = np.std(nba13.column('Height'))
sd_height
3.4505971830275546

俄克拉荷马城雷霆队的高大中锋哈希姆·塔比特(Hasheem Thabeet)是最高的球员,身高87英寸。

[In ]:
nba13.sort('Height', descending=True).show(3)
<IPython.core.display.HTML object>

塔比特比平均身高高出约8英寸。

[In ]:
87 - mean_height
7.934653465346528

这是一个离差,约是标准差的2.3倍:

[In ]:
(87 - mean_height)/sd_height
2.2995015194397923

换句话说,最高球员的身高比平均值高出约2.3个标准差。

以赛亚·托马斯(Isaiah Thomas)身高69英寸,是2013年NBA最矮的两名球员之一。他的身高比平均值低约2.9个标准差。

[In ]:
nba13.sort('Height').show(3)
<IPython.core.display.HTML object>
[In ]:
(69 - mean_height)/sd_height
-2.9169868288775844

我们观察到的是,最高和最矮的球员都离平均身高只有几个标准差。这就是为什么SD是一个有用的分散程度度量的例子。无论直方图的形状如何,平均值和SD一起告诉你很多关于直方图在数轴上的位置信息。

用SD度量分散程度的第一个主要原因

非正式陈述。 在所有数值数据集中,大部分条目都在“平均值 $\pm$ 几个SD”的范围内。

现在,暂且抑制住想知道“大部分”和“几个”这类模糊词语确切含义的欲望。我们将在本节后面使它们精确化。让我们先在更多例子的背景下考察这个陈述。

我们已经看到,NBA球员的所有身高都在“平均值 $\pm$ 3个SD”的范围内。

年龄方面呢?以下是年龄分布的直方图,以及均值和SD。

[In ]:
nba13.select('Age in 2013').hist(bins=np.arange(15, 45, 1))
Histogram with 'Age in 2013' on the x-axis extending from x=15 to x=45 and 'Percent per unit' on the y-axis. The bars increase in height until they reach a peak between about x=23 to x=26. Then the bars generally decrease in height with a few spikes around x=27, and x=34.
[In ]:
ages = nba13.column('Age in 2013')
mean_age = np.mean(ages)
sd_age = np.std(ages)
mean_age, sd_age
(26.19009900990099, 4.321200441720307)

平均年龄略高于26岁,SD约为4.3年。

年龄与平均值相差多少?就像我们处理身高一样,让我们看一个例子。

朱万·霍华德(Juwan Howard)是最年长的球员,40岁。

[In ]:
nba13.sort('Age in 2013', descending=True).show(3)
<IPython.core.display.HTML object>

霍华德的年龄比平均值高出约3.2个标准差。

[In ]:
(40 - mean_age)/sd_age
3.1958482778922357

我们在身高和年龄上观察到的在很大一般性上成立。对于所有列表,大部分条目离平均值的距离不超过2或3个标准差。

切比雪夫界

俄罗斯数学家帕夫努蒂·切比雪夫(Pafnuty Chebychev,1821-1894)证明了一个结果,使我们的粗略陈述变得精确。

对于所有列表和所有数字 $z$,位于“平均值 $\pm z$ 个SD”范围内的条目比例至少为 $1 - \frac{1}{z^2}$。

需要注意的是,该结果给出的是一个界(bound),而不是一个精确值或近似值。

这个结果之所以强大,是因为它对所有列表——所有分布,无论多么不规则——都成立。

具体来说,它表明对于每个列表:

  • 在“平均值 $\pm$ 2个SD”范围内的比例至少为 1 - 1/4 = 0.75

  • 在“平均值 $\pm$ 3个SD”范围内的比例至少为 1 - 1/9 $\approx$ 0.89

  • 在“平均值 $\pm$ 4.5个SD”范围内的比例至少为 1 - 1/$\boldsymbol{4.5^2}$ $\approx$ 0.95

正如我们上面指出的,切比雪夫的结果给出了一个下界,而不是一个精确的答案或近似值。例如,在“平均值 $\pm ~2$个SD”范围内的条目百分比可能比75%大得多,但不能小于75%。

标准单位

在上面的计算中,量 $z$ 度量的是“标准单位”(standard units),即高于平均值多少个标准差。

有些标准单位的值为负,对应低于平均值的原始值。其他标准单位的值为正。但无论列表的分布是什么样子,切比雪夫界表明标准单位通常会在(-5, 5)范围内。

要将一个值转换为标准单位,首先找出它离平均值有多远,然后将该离差与标准差进行比较。

$$ z ~=~ \frac{\mbox{值 }-\mbox{ 平均值}}{\mbox{SD}} $$

正如我们将看到的,标准单位在数据分析中经常使用。因此,定义一个将数字数组转换为标准单位的函数是很有用的。

[In ]:
def standard_units(numbers_array):
    "Convert any array of numbers to standard units."
    return (numbers_array - np.mean(numbers_array))/np.std(numbers_array)    

示例

正如我们在前面章节中看到的,表格 united 包含一列 Delay,由2015年夏季美联航数千次航班的起飞延误时间(分钟)组成。我们将通过对延误时间列应用函数 standard_units 来创建一个名为 Delay (Standard Units) 的新列。这使我们能够查看所有以分钟为单位的延误时间及其对应的标准单位值。

[In ]:
united = Table.read_table(path_data + 'united_summer2015.csv')
united = united.with_column(
    'Delay (Standard Units)', standard_units(united.column('Delay'))
)
united
Date   | Flight Number | Destination | Delay | Delay (Standard Units)
6/1/15 | 73            | HNL         | 257   | 6.08766
6/1/15 | 217           | EWR         | 28    | 0.287279
6/1/15 | 237           | STL         | -3    | -0.497924
6/1/15 | 250           | SAN         | 0     | -0.421937
6/1/15 | 267           | PHL         | 64    | 1.19913
6/1/15 | 273           | SEA         | -6    | -0.573912
6/1/15 | 278           | SEA         | -8    | -0.62457
6/1/15 | 292           | EWR         | 12    | -0.117987
6/1/15 | 300           | HNL         | 20    | 0.0846461
6/1/15 | 317           | IND         | -10   | -0.675228
... (13815 rows omitted)

我们能看到的这些标准单位与基于切比雪夫界的预期一致。大多数规模很小;只有一个超过6。

但当我们从高到低排序延误时间时,发生了相当令人震惊的事情。我们能看到的这些标准单位极高!

[In ]:
united.sort('Delay', descending=True)
Date    | Flight Number | Destination | Delay | Delay (Standard Units)
6/21/15 | 1964          | SEA         | 580   | 14.269
6/22/15 | 300           | HNL         | 537   | 13.1798
6/21/15 | 1149          | IAD         | 508   | 12.4453
6/20/15 | 353           | ORD         | 505   | 12.3693
8/23/15 | 1589          | ORD         | 458   | 11.1788
7/23/15 | 1960          | LAX         | 438   | 10.6722
6/23/15 | 1606          | ORD         | 430   | 10.4696
6/4/15  | 1743          | LAX         | 408   | 9.91236
6/17/15 | 1122          | HNL         | 405   | 9.83637
7/27/15 | 572           | ORD         | 385   | 9.32979
... (13815 rows omitted)

这表明数据有可能比平均值高出许多个标准差(并且航班可能延误近10个小时)。延误的最高值在标准单位中超过14。

然而,这些极端值的比例很小,切比雪夫界仍然成立。例如,让我们计算在“平均值 $\pm$ 3个SD”范围内的延误时间百分比。这相当于标准单位在(-3, 3)范围内的时间百分比。如下计算,约为98%,与切比雪夫界“至少89%”一致。

[In ]:
within_3_sd = united.where('Delay (Standard Units)', are.between(-3, 3))
within_3_sd.num_rows/united.num_rows
0.9790235081374322

延误时间的直方图如下所示,横轴为标准单位。根据上表,右尾一直延伸到 $z=14.27$ 标准单位(580分钟)。直方图中 $z=-3$ 到 $z=3$ 范围之外的面积约为2%,由微小的碎片组成,在直方图中基本不可见。

[In ]:
united.hist('Delay (Standard Units)', bins=np.arange(-5, 15.5, 0.5))
plots.xticks(np.arange(-6, 17, 3));
Histogram with 'Delay (Standard Units) on the x-axis and 'Percent per unit' on the y-axis. The x axis extends from -6 to 15 but the majority of the data sits between approximately x=-1.5 to x=3. THe tallest bar is much taller than the others, by about 2 or 3 times. After the tallest bar, the heights drop off dramatically.