在Python中将Z分数转换为p值

77 投票
7 回答
94601 浏览
提问于 2025-04-16 02:52

怎么把一个Z分数Z分布(标准正态分布,高斯分布)转换成一个p呢?我还没找到在Scipy的stats模块里能做到这一点的神奇函数,但应该是有的。

7 个回答

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

我认为累积分布函数(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
75

我更喜欢正态分布的生存函数(上尾概率),因为这个函数的名字更能说明问题:

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种分布之一。

norm.sf这个函数也会调用scipy.special中的相应函数,就像gotgenes的例子一样。

生存函数(sf)有一个小优势:在处理接近1的分位数时,它的数值精度应该比使用累积分布函数(cdf)要好。

撰写回答