1.3 SciPy

SciPy为Python添加了大量的函数库。由于SciPy在后端使用NumPy,因此通常这两个组件需要一起安装。关于SciPy的完整指南,可以查阅其官方文档。

在本书中,我们主要聚焦于scipy.stats模块。启动Python,执行如下代码:

>>> import scipy
>>> scipy.__version__
'1.2.1'

以上代码将加载SciPy并方便你确认其版本是否符合最低要求,通常更新的版本在本书中也适用。

下面做几个简单的小实验。

>>> from scipy.stats import ttest_ind
>>> a = np.random.normal(0,1,1000)
>>> b = np.random.normal(0,0.5,1000)
>>> c = np.random.normal(0.1,1,1000)
>>> ttest_ind(a,b)
Ttest_indResult(statistic=-0.027161815649563964, pvalue=0.9783333836992686)
>>> ttest_ind(a,c)
Ttest_indResult(statistic=-2.295584443456226, pvalue=0.021802794508002675)

我们首先加载NumPy,然后从SciPy的stats模块中导入ttest_ind函数。该函数能够接收两个集合作为参数,比如来自两个类别的数值集合,然后回答如下问题:这两个集合的均值是否相同?或者更准确地说,回答我们有多大把握相信这两组数据来自同样的生成过程。解决这个问题的一种经典算法就是t检验(t-test)。评估方式则是看结果中的p值,即pvalue一项。你可以把p值理解为,如果两组数据来自同样的生成过程,那么这两组数据的均值差有多大概率与我们观测的结果一致。如果概率接近1,则可以基本相信这两组数据的生成过程相同。

a、b和c是一维数组,其中的元素(有1000个值)都取自高斯曲线(也称为正态曲线)。我们会在后面详细说明数据的生成过程,这里你只需要理解每个数值都取自一条钟形曲线,这种曲线中间的部分相比边缘更有可能被取样。normal函数的前两个参数分别定义均值和标准差,后者用于衡量曲线的宽度。也就是说,标准差越大,曲线的形状越扁平,曲线越宽。

在这个例子中,我们预期a和b是十分相似的两组数据,因为它们的均值都是0.0,只不过它们取样的钟形曲线在形状上存在稍许差异。相比而言,c的均值为0.1。我们希望t检验算法的结果能够体现这两者之间的差异,也就是告诉我们a和c不大可能来自同样的生成过程。

函数ttest_ind执行t检验并输出包含pvalue一项的信息。正如我们所料,输入a和b,得到的p值约为0.98。这表示如果两组数据来自同一生成过程,那么这两组数据的均值差异有98%的概率与我们给出的数据一致。相比而言,当输入a和c时,得到的p值约为0.027。这表示如果两组数据的生成过程相同,那么它们的均值差异只有3%的概率符合我们给出的数据。因而我们可以推断a和c来自不同的生成过程。我们称这两组数据具有统计显著性差异。

传统上,我们认为p值小于0.05就具有统计显著性了。然而使用这个阈值有些武断,最近在复现一些实验,尤其是软科学中的实验时,大家发现这个阈值应该设置得更为严格。以p值等于0.05为阈值,这意味着每20次实验中就有1次结论错误(1/20 = 0.05),这样的阈值过于宽泛。应该说,p值接近0.05只能证明某个结论有可能是事实,值得我们投入更多精力(和更大规模的数据)去做进一步研究。