将Z得分(Z值,标准分数)转换为Python中正态分布的p值

76

我已经在这里开始了一个项目:http://statsandprobability.codeplex.com/ - user123976
7个回答

72

我比较喜欢正态分布的生存函数(上尾概率),因为这个函数名更加具有信息性:

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)更好。


45
我觉得累积分布函数(cdf)比生存函数更好。生存函数定义为1-cdf,可能不正确地传达了语言模型在方向性百分位数方面使用的假设。同时,百分点函数(ppf)是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

你能提供一个更完整的代码答案,展示如何将Z分数向量转换为p值向量吗? - Robin De Schepper
1
@RobinDeSchepper 已添加 - Myles Baker
1
我可能错了,但是我在上面的解决方案中没有看到p值,只看到z分数和百分位数。我非常喜欢这个解决方案,只是我没有看到任何p值,它们似乎都是z分数。 - George Hayward

12

啊哈!我找到了: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)

奇怪的术语,“Z分布”而不是“正态曲线”。在这种情况下,我可能会将 Z 得分称为标准差。 - Nick T
嗯,Z分布等于“标准正态分布”等于N(0, 1)。话虽如此,你的观点很好。我已经更新了问题以反映相同概念的各种术语。 - gotgenes

8

Python 3.8 开始,标准库提供了 NormalDist 对象作为 statistics 模块的一部分。

它可以用于应用反向累积分布函数 (inv_cdf,也称为分位函数百分点函数) 和累积分布函数(cdf):

NormalDist().inv_cdf(0.95)
# 1.6448536269514715
NormalDist().cdf(1.64)
# 0.9494974165258963

3

从公式来看:

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)))

1
这不是最好的解决方案;它不像上面的答案一样矢量化。 - hlin117
3
你可以通过使用scipy中的erfsqrt来替换math.erfmath.sqrt,从而轻松获得向量化版本。 - NullSpace
如果z不是向量,这是最佳解决方案。 - Erik Aronesty

1
p_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

Python中的概率密度函数(PDF)函数生成的值为从入门/AP统计书中的z分数表中抽取的p值。

0

对于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)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接