在数据框上按组进行单边单样本 T 检验?

One-sided one sample T test by group on data frame?

我正在尝试在 python 中的 pandas 数据帧上按组执行单侧单样本 T 检验。我觉得我已经很接近了,但我无法关闭最后一点。我试图遵循与这些问题类似的问题 (One Sided One Sample T Test Python and )。

比如说我有一个数据框df

df = pd.DataFrame({'ID': ['A', 'A', 'A', 'A', 'A', 
                          'B', 'B', 'B', 'B', 'B', 
                          'C', 'C', 'C', 'C', 'C'],
                   'value': [0.200, 0.201, 0.189, 0.199, 0.205, 
                             0.220, 0.225, 0.209, 0.218, 0.230, 
                             0.308, 0.291, 0.340, 0.444, 0.275]})

我想生成一个只有两列的新数据框 df_pval:'ID' 和单边样本 T 检验的 p 值。我可以在 R 中这样做:

library(dplyr)

df_pval <- df %>%
     group_by(ID) %>%
     summarise(res = list(t.test(value, mu = 0.220, alternative = 'greater')))

df_pval <- data.frame(ID = df_pval$ID,
     pval = sapply(df_pval$res, function(x) x[['p.value']]))

事实上,现在我使用 os 到 运行 外部 R 脚本来执行此操作,但我知道它必须在 python 中才有可能。我尝试创建一个 'groupby' 对象,然后 运行ning .apply:

df_groupID = df.groupby('ID').agg({'value': list})
df_groupID.apply(lambda x: stats.ttest_1samp(x['value'], 0.220))

但这不起作用。到目前为止,我被困住了。对此问题的任何帮助将不胜感激。预先感谢您,如果之前已经回答过这个问题(我只是不明白解决方案),我们深表歉意。

也许尝试这样的事情(使用 scipy-1.7.3):

import pandas as pd
from scipy import stats
df = pd.DataFrame({'ID': ['A', 'A', 'A', 'A', 'A', 
                          'B', 'B', 'B', 'B', 'B', 
                          'C', 'C', 'C', 'C', 'C'],
                   'value': [0.200, 0.201, 0.189, 0.199, 0.205, 
                             0.220, 0.225, 0.209, 0.218, 0.230, 
                             0.308, 0.291, 0.340, 0.444, 0.275]})
df_groupID = df.groupby('ID').agg({'value': list})

df_groupID['value'] = df_groupID.value.apply(lambda x : stats.ttest_1samp(x, 0.220, alternative='greater').pvalue)
df_groupID = df_groupID.rename(index=str, columns={'value':'pval'})
        pval
ID          
A   0.999335
B   0.457619
C   0.010342

相当于:

library(dplyr)

df <- data.frame(
   ID = c ('A', 'A', 'A', 'A', 'A', 
                          'B', 'B', 'B', 'B', 'B', 
                          'C', 'C', 'C', 'C', 'C'), 
   value = c(0.200, 0.201, 0.189, 0.199, 0.205, 
                             0.220, 0.225, 0.209, 0.218, 0.230, 
                             0.308, 0.291, 0.340, 0.444, 0.275)
)

df_pval <- df %>%
     group_by(ID) %>%
     summarise(res = list(t.test(value, mu = 0.220, alternative = 'greater')))
df_pval <- data.frame(ID = df_pval$ID,
     pval = sapply(df_pval$res, function(x) x[['p.value']]))
print(df_pval)
  ID       pval
1  A 0.99933491
2  B 0.45761885
3  C 0.01034185

对于 one-sided 测试,这应该适用于任何版本的 scipy:

import pandas as pd
from scipy import stats
df = pd.DataFrame({'ID': ['A', 'A', 'A', 'A', 'A', 
                          'B', 'B', 'B', 'B', 'B', 
                          'C', 'C', 'C', 'C', 'C'],
                   'value': [0.200, 0.201, 0.189, 0.199, 0.205, 
                             0.220, 0.225, 0.209, 0.218, 0.230, 
                             0.308, 0.291, 0.340, 0.444, 0.275]})


df.groupby('ID')['value'].apply(lambda x: stats.ttest_1samp(list(x),
                                popmean=0.220).pvalue/2) # divide by 2 for one-sided (alternative='greater' or 'smaller')

给出:

ID
A    0.000665
B    0.457619
C    0.010342