如何将Z分数从Z分布(标准正态分布,高斯分布)转换为p值?我还没有在Scipy的stats
模块中找到这个神奇的函数,但一定存在。
如何将Z分数从Z分布(标准正态分布,高斯分布)转换为p值?我还没有在Scipy的stats
模块中找到这个神奇的函数,但一定存在。
我比较喜欢正态分布的生存函数(上尾概率),因为这个函数名更加具有信息性:
p_values = scipy.stats.norm.sf(abs(z_scores)) #one-sided
p_values = scipy.stats.norm.sf(abs(z_scores))*2 #twosided
"norm"是scipy.stats中约90个分布之一。
与gotgenes示例中的情况类似,norm.sf也调用了scipy.special中相应的函数。
使用生存函数(sf)的一个小优势是在接近1的分位数处,数值精度应该比使用累积分布函数(cdf)更好。
>>> import scipy.stats as st
>>> st.norm.ppf(.95)
1.6448536269514722
>>> st.norm.cdf(1.64)
0.94949741652589625
编辑: 用户请求例子说明“向量”:
import numpy as np
vector = np.array([.925, .95, .975, .99])
p_values = [st.norm.ppf(v) for v in vector]
f_values = [st.norm.cdf(p) for p in p_values]
for p,f in zip(p_values, f_values):
print(f'p: {p}, \tf: {f}')
产出:
p: 1.4395314709384563, f: 0.925
p: 1.6448536269514722, f: 0.95
p: 1.959963984540054, f: 0.975
p: 2.3263478740408408, f: 0.99
啊哈!我找到了:scipy.special.ndtr
!这似乎也在 scipy.stats.stats.zprob
下面(它只是指向 ndtr
)。
具体来说,对于一个一维的 numpy.array
实例 z_scores
,可以通过以下方式获得其 p 值:
p_values = 1 - scipy.special.ndtr(z_scores)
或者另一种选择
p_values = scipy.special.ndtr(-z_scores)
N(0, 1)
。话虽如此,你的观点很好。我已经更新了问题以反映相同概念的各种术语。 - gotgenes从 Python 3.8
开始,标准库提供了 NormalDist
对象作为 statistics
模块的一部分。
它可以用于应用反向累积分布函数 (inv_cdf
,也称为分位函数或百分点函数) 和累积分布函数(cdf
):
NormalDist().inv_cdf(0.95)
# 1.6448536269514715
NormalDist().cdf(1.64)
# 0.9494974165258963
从公式来看:
import numpy as np
import scipy.special as scsp
def z2p(z):
"""From z-score return p-value."""
return 0.5 * (1 + scsp.erf(z / np.sqrt(2)))
erf
和sqrt
来替换math.erf
和math.sqrt
,从而轻松获得向量化版本。 - NullSpacep_value = scipy.stats.norm.pdf(abs(z_score_max)) #one-sided test
p_value = scipy.stats.norm.pdf(abs(z_score_max))*2 # two - sided test
对于Scipy爱好者来说,虽然这是一个老问题,但仍然相关。我们不仅可以使用正常分布,还可以使用其他分布,因此这里提供了几个更多分布的解决方案:
def get_p_value_normal(z_score: float) -> float:
"""get p value for normal(Gaussian) distribution
Args:
z_score (float): z score
Returns:
float: p value
"""
return round(norm.sf(z_score), decimal_limit)
def get_p_value_t(z_score: float) -> float:
"""get p value for t distribution
Args:
z_score (float): z score
Returns:
float: p value
"""
return round(t.sf(z_score), decimal_limit)
def get_p_value_chi2(z_score: float) -> float:
"""get p value for chi2 distribution
Args:
z_score (float): z score
Returns:
float: p value
"""
return round(chi2.ppf(z_score, df), decimal_limit)