如何使用numpy/scipy进行双样本单侧t检验

54
在R中,可以通过使用以下方法来执行双样本单侧t检验:
> A = c(0.19826790, 1.36836629, 1.37950911, 1.46951540, 1.48197798, 0.07532846)
> B = c(0.6383447, 0.5271385, 1.7721380, 1.7817880)
> t.test(A, B, alternative="greater")

    Welch Two Sample t-test

data:  A and B 
t = -0.4189, df = 6.409, p-value = 0.6555
alternative hypothesis: true difference in means is greater than 0 
95 percent confidence interval:
 -1.029916       Inf 
sample estimates:
mean of x mean of y 
0.9954942 1.1798523 

在Python世界中,scipy提供了类似的功能ttest_ind,但只能进行双尾t检验。我发现关于这个主题最接近的信息是这个链接,但它似乎更多地是关于在scipy中实现单尾与双尾的政策讨论。
因此,我的问题是是否有人知道如何使用numpy/scipy执行单尾版本的测试的示例或说明?

3
scipy 版本 1.6.0 开始,在 scipy.stats.ttest_ind 中进行单侧 t 检验现在成为一个参数。现在您可以更改 alternative 参数。 - MattR
6个回答

94

从您的邮件列表链接中:

因为单侧检验可以从双侧检验中推出。(对于对称分布,单侧p值只是双侧p值的一半)

它还指出scipy总是将测试统计量作为有符号数给出。这意味着,在进行双尾检验时,如果p/2 < alpha and t > 0,则拒绝大于测试的零假设;如果p/2 < alpha and t < 0,则拒绝小于测试的零假设。


1
我对t的这个表述有点困惑。H0:第一个比第二个大 first = np.random.normal(3,2,400); second = np.random.normal(6,2,400); t, p = stats.ttest_ind(first, second, axis=0, equal_var=True) t-stat = -23.0, p-value/2 = 1.33e-90 因此,我有一个大于测试的零假设,但是t<0,这意味着我不能拒绝零假设? - Alina
5
@Tonja:你得到了一个负的t统计值,因为第一个均值和第二个均值之间的差异是负数。scipy.stats.ttest_ind(a, b) 计算的是 mean(a)-mean(b) 的均值差异,所以如果你想要证明的备择假设是 mean(second)>mean(first) ,那么你可以调用 scipy.stats.ttest_ind(second, first) ,这样你就不必担心符号问题。在这种情况下,如果 p-value/2 < alpha ,即 t>t_crit(df) ,则拒绝原假设(即 mean(second)<=mean(first) )。 - bpirvu
t_crit(df)是自由度为df的临界t值,基本上是sample_size_1 + sample_size_2 -2,可以从这样的统计表中读取 http://users.stat.ufl.edu/~athienit/Tables/tables。 - bpirvu
...对于单侧检验(或者这个链接http://www.sjsu.edu/faculty/gerstman/StatPrimer/t-table.pdf 用于双侧检验)。 - bpirvu

33

由于评论的一般限制导致无法正确地写下我的见解,我试图将它们作为完整的答案提供。首先,让我们正确地阐述我们的调查问题。我们正在调查的数据是

A = np.array([0.19826790, 1.36836629, 1.37950911, 1.46951540, 1.48197798, 0.07532846])
B = np.array([0.6383447, 0.5271385, 1.7721380, 1.7817880])

使用样本均值

A.mean() = 0.99549419
B.mean() = 1.1798523

我假设因为B的平均值明显大于A的平均值,您想要检查这个结果是否具有统计学意义。

因此,我们有零假设

H0: A >= B

我们希望拒绝原假设,转而采用备择假设。
H1: B > A

现在当您调用scipy.stats.ttest_ind(x, y)时,它会对x.mean()-y.mean()的值进行假设检验,这意味着为了在整个计算过程中得到正值(这简化了所有考虑),我们需要调用:
stats.ttest_ind(B,A)

我们使用 stats.ttest_ind(B,A) 的替代方法可以得到以下答案:

  • t-value = 0.42210654140239207
  • p-value = 0.68406235191764142

根据文档,这是一个双尾t检验的输出结果,因此在进行单侧检验时需要将p值除以2。所以,根据您选择的显著水平 alpha ,您需要:

p/2 < alpha

为了拒绝零假设H0,对于alpha=0.05,这显然不是情况,因此你不能拒绝H0。另一种在不进行任何tp代数运算的情况下决定是否拒绝H0的方法是查看t值并将其与所需置信水平(例如95%)的关键t_crit值进行比较,以适用于您的问题的自由度df数量。由于我们有:
df = sample_size_1 + sample_size_2 - 2 = 8

我们可以从类似这个统计表中获取以下信息:

t_crit(df=8, confidence_level=95%) = 1.860

我们明确地拥有
t < t_crit

因此,我们再次得出相同的结论,即我们无法拒绝H0

假设我只想要每个单尾检验的p值:stats.ttest_ind(B,A)和stats.ttest_ind(A,B)。我该如何思考?如果t统计量<0,应该取1-p/2吗? - CHRD

7
    from scipy.stats import ttest_ind  
    
    def t_test(x,y,alternative='both-sided'):
            _, double_p = ttest_ind(x,y,equal_var = False)
            if alternative == 'both-sided':
                pval = double_p
            elif alternative == 'greater':
                if np.mean(x) > np.mean(y):
                    pval = double_p/2.
                else:
                    pval = 1.0 - double_p/2.
            elif alternative == 'less':
                if np.mean(x) < np.mean(y):
                    pval = double_p/2.
                else:
                    pval = 1.0 - double_p/2.
            return pval

    A = [0.19826790, 1.36836629, 1.37950911, 1.46951540, 1.48197798, 0.07532846]
    B = [0.6383447, 0.5271385, 1.7721380, 1.7817880]

    print(t_test(A,B,alternative='greater'))
    0.6555098817758839

4

当零假设为Ho: P1>=P2,备选假设为Ha: P1<P2时。为了在Python中测试它,您可以写ttest_ind(P2,P1)(请注意位置是先输入P2)。

first = np.random.normal(3,2,400)
second = np.random.normal(6,2,400)
stats.ttest_ind(first, second, axis=0, equal_var=True)

您将得到以下结果:Ttest_indResult(statistic=-20.442436213923845,pvalue=5.0999336686332285e-75) 在Python中,当statstic<0时,您的实际p值实际上是real_pvalue = 1-output_pvalue/2= 1-5.0999336686332285e-75/2,约为0.99。由于您的p值大于0.05,因此无法拒绝6>=3的零假设。当statstic>0时,实际z分数等于-statstic,实际p值等于pvalue/2。
Ivc的答案应该是当(1-p/2) < alpha and t < 0时,您可以拒绝小于假设。

当我阅读到你的帖子时,我感到相当惊讶。依据我的看法,在单面 p 值中,p 应该始终为 out_p/2。你能否给我提供一些关于 (1-p/2) 的相关文档呢? - Chau Pham
根据文档显示,只有当参数equal_var设置为False时,stats.ttest_ind()才能执行单尾假设检验。因此,您的示例展示了双尾假设检验,是吗? - Yongfeng

2

基于 R 中的此函数:https://www.rdocumentation.org/packages/stats/versions/3.6.2/topics/t.test

def ttest(a, b, axis=0, equal_var=True, nan_policy='propagate',
          alternative='two.sided'):        
    tval, pval = ttest_ind(a=a, b=b, axis=axis, equal_var=equal_var,
                           nan_policy=nan_policy)
    if alternative == 'greater':
        if tval < 0:
            pval = 1 - pval / 2
        else:
            pval = pval / 2
    elif alternative == 'less':
        if tval < 0:
            pval /= 2
        else:
            pval = 1 - pval / 2
    else:
        assert alternative == 'two.sided'
    return tval, pval

-2

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