scipy.stats.

normaltest#

scipy.stats.normaltest(a, axis=0, nan_policy='propagate', *, keepdims=False)[source]#

测试样本是否不同于正态分布。

此函数检验样本来自正态分布的零假设。它基于 D’Agostino 和 Pearson 的测试,该测试结合偏度和峰度以产生正态性的总览检验 [1][2]

参数 :
a类数组

包含要测试的样本的数组。必须包含至少八个观察值。

axis整数或 None,默认值:0

如果为整数,则为计算统计量的输入的轴。输入的各个轴切片(例如行)的统计量将出现在输出的对应元素中。如果 None,则在计算统计量之前将对输入进行拉平。

nan_policy{‘propagate’,‘omit’,‘raise’}

定义如何处理输入的 NaN。

  • propagate:如果在沿其计算统计信息的轴分块(例如,行)中存在 NaN,则输出的相应条目将为 NaN。

  • omit:执行计算时会忽略 NaN。如果在沿其计算统计信息的轴分块中缺少足够的数据,则输出的相应条目将为 NaN。

  • raise:如果存在 NaN,则将引发 ValueError

keepdimsbool,默认为 False

如果将其设置为 True,则被还原的轴将作为尺寸为 1 的尺寸保留在结果中。使用此选项,结果将对输入数组广播正确。

返回:
statistic浮点数或数组

s^2 + k^2,其中 sskewtest 返回的 Z 分数,kkurtosistest 返回的 Z 分数。

pvalue浮点数或数组

假设检验的 2-侧卡方分布概率。

备注

从 SciPy 1.9 开始,np.matrix 输入(不推荐用于新代码)将在执行计算之前转换为 np.ndarray。在这种情况下,输出将是标量或形状适当的 np.ndarray,而不是 2D np.matrix。类似地,虽然会忽略掩码数组中掩码元素,但输出将是标量或 np.ndarray,而不是掩码为 mask=False 的掩码数组。

参考文献

[1] (1,2)

D’Agostino, R. B. (1971),“中等和大样本量数据的正态性总体检验”,Biometrika,58,341-348

[2] (1,2)

D’Agostino, R. 和 Pearson, E. S. (1973),“偏离正态性的检验”,Biometrika,60,613-622

[3]

Shapiro, S. S., & Wilk, M. B. (1965)。正态性方差检验(完整样本)。Biometrika,52(3/4),591-611。

[4]

B. Phipson 和 G. K. Smyth。“置换 p 值绝不应该为零:当置换随机抽取时计算精确 p 值”。统计遗传学和分子生物学应用 9.1 (2010)。

[5]

Panagiotakos, D. B.(2008)。生物医学研究中 p 值的作用。开放的心脏病学杂志,2,97。

示例

假设我们希望从测量中推断出某个医学研究中的成年男性的体重分布是否服从正态分布 [3]。体重(磅)记录在 x 数组中。

>>> import numpy as np
>>> x = np.array([148, 154, 158, 160, 161, 162, 166, 170, 182, 195, 236])

正态性检验由 [1][2] 开始,方法是根据样本偏度和峰度计算一个统计数据。

>>> from scipy import stats
>>> res = stats.normaltest(x)
>>> res.statistic
13.034263121192582

(该检验警告我们的样本观测值太少,无法执行该检验。我们会在该示例的结尾处重新讨论这一点。)由于正态分布的偏度为零,峰度(“过剩”或“Fisher”)为零,因此对于从正态分布采样的样本,该统计数据的取值往往较低。

检验通过比较统计数据的观测值和原假设分布(该分布在权重从正态分布中抽样的原假设下得出统计值分布)来进行。对于这个正态性检验,非常大样本的原假设分布是具有两个自由度的卡方分布。

>>> import matplotlib.pyplot as plt
>>> dist = stats.chi2(df=2)
>>> stat_vals = np.linspace(0, 16, 100)
>>> pdf = dist.pdf(stat_vals)
>>> fig, ax = plt.subplots(figsize=(8, 5))
>>> def plot(ax):  # we'll reuse this
...     ax.plot(stat_vals, pdf)
...     ax.set_title("Normality Test Null Distribution")
...     ax.set_xlabel("statistic")
...     ax.set_ylabel("probability density")
>>> plot(ax)
>>> plt.show()
../../_images/scipy-stats-normaltest-1_00_00.png

该比较通过 p 值进行量化:原假设分布中大于或等于观测统计值的值的比例。

>>> fig, ax = plt.subplots(figsize=(8, 5))
>>> plot(ax)
>>> pvalue = dist.sf(res.statistic)
>>> annotation = (f'p-value={pvalue:.6f}\n(shaded area)')
>>> props = dict(facecolor='black', width=1, headwidth=5, headlength=8)
>>> _ = ax.annotate(annotation, (13.5, 5e-4), (14, 5e-3), arrowprops=props)
>>> i = stat_vals >= res.statistic  # index more extreme statistic values
>>> ax.fill_between(stat_vals[i], y1=0, y2=pdf[i])
>>> ax.set_xlim(8, 16)
>>> ax.set_ylim(0, 0.01)
>>> plt.show()
../../_images/scipy-stats-normaltest-1_01_00.png
>>> res.pvalue
0.0014779023013100172

如果 p 值“小” - 也就是说,从正态分布总体(产生该统计值如此极端的取值)中抽样数据的概率很低 - 这可能会被视为对原假设的证据,而非备择假设:权重不是从正态分布中抽取的。注意

  • 逆否命题不成立;也就是说,该检验不用于为原假设提供证据。

  • 将被视为“小”的该值的阈值是一个选择,应当在分析数据前做出 [4],同时考虑误报(错误地拒绝原假设)和 漏报(未能拒绝错误原假设)的风险。

注意,卡方分布提供了原假设分布的渐近近似;它仅精确适用于具有许多观测值的样本。这就是我们在示例开始时收到警告的原因;我们的样本相当小。在这种情况下,scipy.stats.monte_carlo_test 可能会提供确切的 p 值的更准确的随机近似值。

>>> def statistic(x, axis):
...     # Get only the `normaltest` statistic; ignore approximate p-value
...     return stats.normaltest(x, axis=axis).statistic
>>> res = stats.monte_carlo_test(x, stats.norm.rvs, statistic,
...                              alternative='greater')
>>> fig, ax = plt.subplots(figsize=(8, 5))
>>> plot(ax)
>>> ax.hist(res.null_distribution, np.linspace(0, 25, 50),
...         density=True)
>>> ax.legend(['aymptotic approximation (many observations)',
...            'Monte Carlo approximation (11 observations)'])
>>> ax.set_xlim(0, 14)
>>> plt.show()
../../_images/scipy-stats-normaltest-1_02_00.png
>>> res.pvalue
0.0082  # may vary

此外,尽管它们具有随机性,但以这种方式计算的 p 值可以用来确切控制原假设的错误拒绝率 [5]