十四、数据科学导论------数学基础之统计
第1关:统计基础之数据描述
任务描述
本关任务:对输入数据计算相关指标。
相关知识
为了完成本关任务,你需要掌握:1.如何对数据进行描述,2.如何使用 python 计算。
描述单个数据集
假设某天公司领导来问你要一些关于你的成员有多少朋友的描述。对任何数据集,最简单的描述方法就是数据本身:
num_friends = [100, 49, 41, 40, 25,
......等等许多
]
对足够小的数据集来说,这甚至可以说是最好的描述方法。但随着数据规模变大,这就显得笨拙又含混了。为此,我们使用统计来提炼和表达数据的相关特征。
首先,我们通过 Counter 和 plt.bar() 把你的朋友数绘成直方图:
from collections import Counter
friend_counts = Counter(num_friends)
xs = range(101) # 最大值是100
ys = friend_counts\[x for x in xs] # height刚好是朋友的个数
plt.bar(xs, ys)
plt.axis(0, 101, 0, 25)
plt.title("朋友数的直方图")
plt.xlabel("朋友个数")
plt.ylabel("人数")
plt.show()

不幸的是,这幅图难以用来进行交流,所以你需要再提炼一些统计量。数据点个数大概就是最简单的统计量了:
um_points = len(num_friends) # 204
largest_value = max(num_friends) # 100
smallest_value = min(num_friends) # 1
中心倾向
我们常常希望了解数据中心位置的一些概念。一个常用的方法是使用均值,即用数据和除以数据个数:
def mean(x):
return sum(x) / len(x)
mean(num_friends) # 7.333333
如果有两个数据点,均值就是两点的中间点。随着数据点的增加,均值点会移动,但是它始终取决每个点的取值。
还有一个值是中位数,它是指数据中间点的值(如果数据点的个数是奇数)或者中间两个点的平均值(如果数据点的个数是偶数)和均值不同中位数,并不依赖于每一个数据的值。
均值的计算会随着数据变化而平稳地变化。如果有 n 个数据点,其中某一个点的值增加了 e,则均值随之增加 e/n。(这使得均值适用于各种微分运算)但是为了计算中位数,得先对数据排序。并且,如果其中一个数据点的值增加了 e,那么中位数有可能也增加 e,有可能增加一个小于 e 的数,也有可能根本不变(这取决于其他的数据)。
同时,均值对数据中的异常值非常敏感。如果最具人缘的用户有 200 个朋友,均值会上升至 7.82,而中位数不变。如果异常值属于不良数据,那么均值会误导我们。
中位数的一个泛化概念是分位数,它表示少于数据中特定百分比的一个值。
def quantile(x, p):
p_index = int(p * len(x))
return sorted(x)p_index
quantile(num_friends, 0.10) # 1
quantile(num_friends, 0.25) # 3
quantile(num_friends, 0.75) # 9
quantile(num_friends, 0.90) # 13
还有一个不太常用的概念众数(mode),它是指出现次数最多的一个或多个数:
def mode(x):
counts = Counter(x)
max_count = max(counts.values())
return x_i for x_i, count in counts.iteritems() if count == max_count
mode(num_friends) # 1 和 6
离散度
离散度是数据的离散程度的一种度量。通常,如果它所统计的值接近零,则表示数据聚集在一起,离散程度很小,如果值很大,则表示数据的离散度很大。
例如,一个简单的度量是极差,指最大元素与最小元素的差:
def data_range(x):
return max(x) - min(x)
data_range(num_friends) # 99
极差恰好为零,意味着数据集中最大值和最小值相等,这种情形只有在x中的元素全部相同时才会发生,意味着数据没有离散。相反,如果极差很大,说明最大元素比最小元素大很多,数据离散度很高。
和中位数一样,极差也不真正依赖于整个数据集。一个只包含 0 和 100 的数据集,和一个包含 0、1 以及很多个 50 的数据集,两者的极差相同。但看起来第一个数据集的离散度"应该"更高。
离散度的另一个更复杂的度量是方差,计算方式如下:
def de_mean(x):
x_bar = mean(x)
return x_i - x_bar for x_i in x
def variance(x):
n = len(x)
deviations = de_mean(x)
return sum_of_squares(deviations) / (n - 1)
variance(num_friends) # 81.54
现在,无论我们的数据是什么单位,所有中心倾向的度量都是同一单位。极差的单位也与此相同。但是,方差的单位是原数据单位的平方。然而,用方差很难给出直观的比较,所以我们更常使用标准差:
def standard_deviation(x):
return math.sqrt(variance(x))
standard_deviation(num_friends) # 9.03
极差和标准差也都有我们之前提到的均值计算常遇到的异常值问题。再看之前的例子,如果我们最具人缘的用户有 200 个朋友,标准差就变为 14.89 ,增加了 60% !一种更加稳健的方案是计算 75% 的分位数和 25% 的分位数之差:
def interquartile_range(x):
return quantile(x, 0.75) - quantile(x, 0.25)
interquartile_range(num_friends) # 6
相对来说,这种计算不易受到一小部分异常值的影响。
编程要求
请仔细阅读右侧代码,结合相关知识,在 Begin-End 区域内进行代码补充,不使用第三方库实现中位数的计算函数,用于计算输入数据的中位数。
测试说明
平台会对你编写的代码进行测试:
测试输入:43,37,27,80,24,22,94,13,28,27
预期输出:27.5
开始你的任务吧,祝你成功!

def student(data):
#********* Begin *********#
复制并排序数据
sorted_data = sorted(data)
n = len(sorted_data)
判断奇偶
if n % 2 == 1:
median = sorted_datan // 2
else:
mid1 = sorted_data(n//2)-1
mid2 = sorted_datan//2
median = (mid1 + mid2) / 2
print(median)
#********* End *********#
第2关:统计基础之相关性
任务描述
本关任务:编写一个能计算协方差的程序。
相关知识
为了完成本关任务,你需要掌握:1.相关的作用,2.如何计算相关系数。
相关
接着上个关卡,假设现在需要知道用户在某个网站上花费时间与其在这个网站上拥有的朋友数相关。通过分析研究流量日志,得到了一个 daily_minutes 列表,这个列表描述了每个用户每天在网页中花费了多长时间。该列表和之前的 num_friends 列表元素对应。
协方差,这个概念是方差的一个对应词。方差衡量了单个变量对均值的偏离程度,而协方差衡量了两个变量对均值的串联偏离程度。
如果向量 x 和向量 y 的对应元素同时大于它们自身序列的均值,或者同时小于它们自身序列的均值,那将为求和贡献一个正值。如果其中一个元素大于自身的均值,而另一个小于自身的均值,那将为求和贡献一个负值。
因此,如果协方差是一个大的正数,就意味着如果 y 很大,那么 x 也很大,或者如果 y 很小,那么 x 也很小。如果协方差为负而且绝对值很大,就意味着 x 和 y 一个很大,而另一个很小。接近零的协方差意味着以上关系都不存在。
相关是更常受到重视的概念,它是由协方差除以两个变量的标准差:
def correlation(x, y):
stdev_x = standard_deviation(x)
stdev_y = standard_deviation(y)
if stdev_x > 0 and stdev_y > 0:
return covariance(x, y) / stdev_x / stdev_y
else:
return 0 # 如果没有变动,相关系数为零
correlation(num_friends, daily_minutes) # 0.25
相关系数没有单位,它的取值在 -1 (完全反相关)和 1 (完全相关)之间。相关值 0.25 代表一个相对较弱的正相关。
但是我们忽略了对数据进行检查:

上图中标出的有 100 位朋友数的用户是明显的异常值,相关系数的计算对异常值非常敏感。所以在进行相关系数的计算时最好先将异常值去除。
相关系数
相关系数为零表示两个变量之间不存在线性关系。但它们之间还可能会存在其他形式的关系。例如,如果:
x = -2, -1, 0, 1, 2
y = 2, 1, 0, 1, 2
那么, x 和 y 的相关系数为 0。但容易看出, x 和 y 之间显然具有某种关系 ------ y 中的每个元素等于 x 中相应元素的绝对值。
然而,有一种关系它们却无法给出,即 x_i 和 mean(x)之间的关系与 y_i 和 mean(y) 之间的关系并没有太大关联。这是一种相关系数试图捕捉的关系。
此外,相关系数无法告诉你关系有多强。例如:
x = -2, 1, 0, 1, 2
y = 99.98, 99.99, 100, 100.01, 100.02
以上这两个变量完全相关,但很有可能这种关系并没有实际意义。
相关和因果
如果 x 和 y 强相关,那么意味着可能 x 引起了 y,或 y 引起了 x,或者两者相互引起了对方,或者存在第三方因素同时引起了 x 和 y,或者什么都不是。
编程要求
请仔细阅读右侧代码,结合相关知识,在Begin-End区域内进行代码补充,不使用第三方库实现协方差函数,并计算输入数据的协方差,输出结果保留2位小数。
测试说明
平台会对你编写的代码进行测试。
测试输入:
34, 32, 2, 27, 27, 23, 39, 39
19, 33, 22, 18, 43, 46, 19, 49
预期输出:
23.16
开始你的任务吧,祝你成功!

def de_mean(x):
x_bar = sum(x) / len(x)
return x_i - x_bar for x_i in x
def dot(v, w):
return sum(v_i * w_i for v_i, w_i in zip(v, w))
def student(x, y):
********* Begin *********#
n = len(x)
求x、y各元素与均值的偏差
dev_x = de_mean(x)
dev_y = de_mean(y)
协方差:点积除以 n‑1
cov = dot(dev_x, dev_y) / (n - 1)
保留两位小数输出
print("{0:.2f}".format(cov))
********* End *********#
有任何问题都可以随时关注私信!