再次考虑之前的一组捐款清单,100, 60,70, 900, 100, 200, 500, 500, 503, 600,1000,1200。我们发现这组数据的均值为477.75。但是,仅仅通过均值,我们不知道所有的捐款是否都在一个狭窄的范围内,比如400到500之间,或者是更大的范围,本例中捐款范围在60~1200。一组数据的极差(range)是最大数和和最小数之间的差值。可能有两组数字,他们的均值相同,但极差却大不相同,因此,了解极差将能够更多地补充关于一组数据的信息,而不仅仅是从均值、中位数和众数中来得到信息。
此程序用于计算上述捐款清单的极差:
'''
Find the range
'''
def find_range(numbers):
lowest = min(numbers)
highest = max(numbers)
# Find the range
r = highest - lowest
return lowest, highest, r
if __name__ == '__main__':
donations = [100, 60, 70, 900, 100, 200, 500, 500, 503, 600, 1000, 1200]
lowest, highest, r = find_range(donations)
print('Lowest : {0} Highest : {1} Range : {2} '.format(lowest, highest, r))
find_range()函数接受一个列表作为参数并计算极差。首先,对列表使用min()、max()函数找到这组数据的最大值和最小值,然后进行减法运算,将range赋值到标签r,main()程序块中进行调用输出,运行程序:
Lowest : 60 Highest : 1200 Range : 1140
这段输出告诉我们,这些天的总捐款数是相当分散的,极差为1140,最大值为1200,最小值为60。
3.4.2 计算方差和标准差极差告诉我们一组数字中的两个极端值之差,但是如果我们想要更多地了解每个数字与均值的差异情况呢?它们都是相似地聚集在均值附近,还是非常不同地接近极端值?有两种相关的离散度的统计量能够告诉我们更多关于这些方面的信息:方差(variance)和标准差(standard deviation)。无论计算哪一个,首先需要计算每个数与均值的差值,而方差是这些差值的平方和的均值。 方差越大意味着这些数字越偏离均值,方差越小意味着这些数字越聚集在均值附近。我们使用公式计算方差
在这个公式中,代表每个数字(在这个例子中是每日捐款数),代表这些数字的均值(平均每日捐款),n是列表中的值的个数(收到捐款的天数)。对于列表中的每个值,我们首先计算该数字与均值的差并对其求平方,然后将所有的平方差加在一起,最后将总和除以数值个数n来求出方差。 如果想要计算标准差,我们所要做的就是求取方差的平方根。在距离均值一个标准差之内的值可认为较为常见,而距离均值三个或更多个标准差的值可以被认为异常少见,我们将这些值称为异常值(outliers)。
为什么我们有方差和标准差这两种计算离散度的方法?因为这两种统计量在不同的情况下都是有用的。回到我们用来计算方差的公式,可以看出方差是以平方单位表示的,因为它是每个值与均值的差值的平方,求平均值后依然还是平方单位。在一些数学公式中,使用这类平方单位会更好。另一方面,标准差以与总体数据相同的单位表示,例如,如果要计算捐赠列表的方差(稍后介绍),结果是以美元平方表示,这并没有太大的意义,而标准差的单位与每个捐款值的单位是相同的(以美元单位表示)。 以下程序计算数字列表的方差和标准差:
'''
Find the variance and standard deviation of a list of numbers
'''
def calculate_mean(numbers):
# Caculate the mean
return sum(numbers) / len(numbers)
def find_differences(numbers):
# Find the mean
mean = caculate_mean(numbers)
# Find the differences from mean
diff = []
for num in numbers:
diff.append(num - mean)
return diff
def caculate_variance(numbers):
# Find the list of differences
diff = find_differences(numbers)
# Find the squared differences
squared_diff = []
for d in diff:
squared_diff.append(d ** 2)
# Find the variance
sum_squared_diff = sum(squared_diff)
variance = sum_squared_diff / len(numbers)
return variance
if __name__ == '__main__':
donations = [100, 60, 70, 900, 100, 200, 500, 500, 503, 600, 1000, 1200]
variance = caculate_variance(donations)
print('The variance of the list of numbers is {0} :'.format(variance))
std = variance ** 0.5
print('The standard deviation of the list of numbers is {0} :'.format(std))
calculate_variance()函数用来计算传入列表的方差。首先,调用find_differences()函数来计算每个数字与均值的差值,该函数以列表的形式返回每个数字与均值的差值。在这个函数内部,调用之前的calculate_mean()函数来计算这组数据的均值。然后这些差值进行求平方操作,并且将其存储在squared_diff[]列表中。接下来使用sum函数对squared_diff[]列表里面的这些平方求和,最后除以数据个数计算方差。main()中计算完方差后,开平方计算标准差。
运行程序:
The variance of the list of numbers is 141047.35416666666 :
The standard deviation of the list of numbers is 375.5627166887931 :
方差和标准差都非常大,这意味着每日捐款数与均值相差很大。现在,让我们比较另一组捐赠列表的方差和标准差,这组列表的均值与之前那组相同。[489, 465, 321, 502, 475, 489, 580, 392, 441, 510, 489, 580]。 在这种情况下,方差和标准差分别为4696.854166666667和68.5335988159579。较小的方差和标准差告诉我们,每个数字更接近均值。下图展示了这一点。
两个列表中数据围绕均值的波动情况
两个捐款列表的均值是相同的,所以两条均值曲线重叠,在图中显示为一条线。然而,第一个列表中的捐款值与均值的差值较大,曲线波动很大,而第二个列表中的捐款值则非常接近于均值,这证实了我们由较小的方差值推断出的结果。
第五节 计算两个数据集之间的相关性在本节中,我们将学习计算一个统计量: 皮尔森相关系数(Pearson correlation coefficient),它告诉我们两组数字之间关系的性质和强度,我将简单地将这个统计量称为相关系数。注意,该系数用于测量线性关系的强度。当两个集合是非线性关系时,我们需要使用其他的方法(不在这里讨论)计算系数。相关系数可以是正数或负数,其大小介于-1和1之间(包括这两个值)。 相关系数为0表示两个量之间没有线性相关。注意,这并不意味着两个量彼此独立,例如,它们之间仍然可能存在非线性关系。系数为1或接近1表示强烈的正相关;系数正好为1表示完全正相关。类似地,系数为-1或接近-1表示强负相关,其中-1表示完全负相关。
相关性和因果关系
在统计学中,你经常会遇到这样的陈述:”相关性并不意味着有因果关系”。这提醒我们,即使两组观察结果彼此强烈相关,也并不意味着一个变量是导致另一个变量的原因。当两个变量强相关时,有时会有第三个因素影响这两个变量并解释其相关性。一个典型的例子是冰淇淋销售量与犯罪率之间的相关性,如果你在一个典型的城市跟踪这两个变量,你可能会发现相关性,但这并不意味着冰淇淋销售会导致犯罪(反之亦然)。冰淇淋的销售量和犯罪率是相互关联的,因为它们都会随着夏季天气变热而上升。当然这并不意味着炎热的天气直接导致犯罪增加,这种相关性背后还有更复杂的原因。
3.5.1 计算相关系数计算相关系数的公式如下:
上述公式中,n是每组数据中数据的个数(两组数据必须具有相等的长度,即数据个数相同)。用x、y来指代这两组数据集(具体指代哪一组不重要)。表示集合x和集合y中各个元素乘积总和;表示集合x元素的总和,表示集合y元素的总和;表示集合x元素总和的平方,表示集合y元素总和的平方;表示集合x元素平方的总和,表示集合y元素平方的总和。
算术来上述各项后,我们可以将其带入公式球相关系数。对于数据量小的列表,可以手算,但随着数据量越来越大,计算量肯定会越来越复杂。
稍后,我们会写一个计算相关系数的程序。在这个程序中我们会使用到zip()函数,它将帮助我们计算两个数据集乘积之和。以下是zip()函数的工作原理:
>>> simple_list1 = [1, 2, 3]
>>> simple_list2 = [4, 5, 6]
>>> for x,y in zip(simple_list1, simple_list2):
print(x, y)
1 4
2 5
3 6
zip()函数返回x和y中一对相应的元素,你可以在循环中使用这些元素来执行其他操作(如演示中的输出)。如果两个列表长度不等,则当较短的列表元素被读取完后,函数终止。
现在,我们准备来编写一个程序来为我们计算相关系数:
def find_corr_x_y(x, y):
n = len(x)
# Find the sum of the products
prod = []
for xi, yi in zip(x, y):
prod.append(xi * yi)
sum_prod_x_y = sum(prod)
sum_x = sum(x)
sum_y = sum(y)
x_square = []
for xi in x:
x_square.append(xi ** 2)
# Find the sum
sum_x_square = sum(x_square)
y_square = []
for yi in y:
y_square.append(yi ** 2)
# Find the sum
sum_y_square = sum(y_square)
# Use formula to calculate correlation
numerator = n * sum_prod_x_y - sum_x * sum_y
denominator_temr1 = n * sum_x_square - sum_x ** 2
denominator_temr2 = n * sum_y_square - sum_y ** 2
denominator = (denominator_temr1 * denominator_temr2) ** 0.5
correlation = numerator / denominator
return correlation
find_corr_x_y()函数接收两个参数x和y,对x数据集和y数据集计算相关系数。在这个函数的开始,定义了一个标签n来指代x数据集的长度。接下来的for循环计算x与y的乘积(第一项乘以第一项,第二项乘以第二项,以此类推)。使用append()函数将其加入到prod[]列表中,这个列表里面存储的是x和y对应项的乘积。
使用sum()函数计算prod[]列表中数据总和,即求出了 ,往下继续使用sum()函数分别计算出x与y数据集的总和,即得到了与,继续往下看,两个for循环来计算出x与y数据集中各项的平方然后分别将其存入到x_square[]与y_square[]中,再对x_square[]与y_square[]分别使用sum()函数,即求得了与。
然后开始按照公式,将算出的各项带入到公式里面进行计算即可,最后返回相关系数。在大众传媒和科学文章中,相关系数是统计研究中经常引用的一个统计量。有时,我们预先知道数据间存在相关性,想进一步了解其强度。我们将在3.7节的“从CSV文件读取数据”中看到这样一个例子。有时,我们只是猜测可能存在相关性,但是必须研究数据来验证事实是否如此(如下例所示)。
3.5.2 高中成绩和大学入学成绩在本节中,我们将虚构一个由10名高中生组成的小组,并研究他们在学校的成绩与他们在大学入学考试中的成绩之间是否有关系。下表列出了我们为研究而假设的数据,我们的实验将基于这些数据。“高中成绩”栏列出学生高中成绩的百分位数,“大学入学考试成绩"栏列出了学生在大学入学考试中成绩的百分位数。
高中成绩和大学入学成绩
要分析这些数据,我们来看看散点图(scatter plot)。下图显示了上述数据集的散点图,x轴代表高中成绩,y轴代表大学入学成绩。
高中成绩和大学入学成绩的散点图
散点图显示,高中成绩较高的学生在大学入学考试中的表现不一定好,反之亦然。有些高中成绩较差的学生在大学入学考试时表现得非常出色,而有些高中成绩优异的学生在大学入学考试中则表现得相对较差。如果计算两个数据集的相关系数(使用前面的程序),我们会看到它大约是0.32,这意味着这两个数据集有- -些相关性,但不是很显著。如果相关性接近1,我们也会在散点图中看到:这些点将更接近于一条直的对角线。
假设上表中显示的高中成绩是数学、科学、英语和社会科学等各科成绩的均值让我们想象一下,与其他科目相比大学考试更重视数学。与其观察学生的高中总成绩不如观察他们的数学成绩,看看是否能更好地预测他们大学考试的成绩。下表现在只显示数学成绩(百分位数)和大学入学考试成绩。相应的散点图如图所示。
高中数学成绩和大学入学数学成绩
现在,散点图(下图)显示了数据点几乎沿着一条直线分布,这表明高中数学成绩与大学入学考试成绩之间存在很高的相关性。在这种情况下,相关系数约为1。借助于散点图和相关系数,我们可以得出结论:高中数学成绩和大学入学考试成绩之间确实存在着显著的相关性。
高中数学成绩和大学入学数学成绩的散点图