【问题标题】:How to get the p-value between two groups after groupby in pandas?如何在熊猫分组后获得两组之间的p值?
【发布时间】:2020-01-03 08:18:28
【问题描述】:

我被困在如何应用自定义函数来计算从 pandas groupby 获得的两组的 p 值。

词汇

test = 0 ==> test
test = 1 ==> control

问题设置

import numpy as np
import pandas as pd
import scipy.stats as ss

np.random.seed(100)
N = 15
df = pd.DataFrame({'country': np.random.choice(['A','B','C'],N),
                   'test': np.random.choice([0,1], N),
                   'conversion': np.random.choice([0,1], N),
                   'sex': np.random.choice(['M','F'], N)

                  })


ans = df.groupby(['country','test'])['conversion'].agg(['size','mean']).unstack('test')
ans.columns = ['test_size','control_size','test_mean','control_mean']
         test_size  control_size  test_mean  control_mean
country                                                  
A                3             3   0.666667      0.666667
B                1             1   1.000000      1.000000
C                4             3   0.750000      1.000000

问题

现在我想再添加两列来获取测试组和对照组之间的 p 值。 但是在我的 groupby 中,我一次只能对一个系列进行操作,我不确定如何使用两个系列来获取 p 值。

到目前为止完成:

def get_ttest(x,y):
    return stats.ttest_ind(x, y, equal_var=False).pvalue

pseudo code:

df.groupby(['country','test'])['conversion'].agg(
['size','mean', some_function_to_get_pvalue])

如何获取 p 值列?

必填答案

我需要获取列 pvalue

的值
         test_size  control_size  test_mean  control_mean  pvalue
country                                                  
A                3             3   0.666667      0.666667   ?
B                1             1   1.000000      1.000000   ?
C                4             3   0.750000      1.000000   ?

【问题讨论】:

  • 这能回答你的问题吗? Calculate pvalue from pandas DataFrame
  • TLDR:你不能只用一个 groupby。您需要按国家+组编写第一个聚合来计算大小、均值和方差(需要自定义聚合函数)。然后,仅按国家/地区聚合以计算 p 值(另一个自定义聚合函数)。整个设置看起来很难看,所以也许只是按国家聚合并明确地完成其余的工作(即通过测试/控制过滤数据帧,然后合并并使用 .apply)会更直观。
  • @Marat 感谢您提供有用的建议。我会更多地研究它。

标签: python pandas numpy scipy p-value


【解决方案1】:

你可以这样做:

import numpy as np
import pandas as pd
import scipy.stats as stats

def get_ttest(x,y,sided=1):
    return stats.ttest_ind(x, y, equal_var=False).pvalue/sided

np.random.seed(100)
N = 15
df = pd.DataFrame({'country': np.random.choice(['A','B','C'],N),
                   'test': np.random.choice([0,1], N),
                   'conversion': np.random.choice([0,1], N),
                   'sex': np.random.choice(['M','F'], N)

                  })


col_groupby = 'country'
col_test_control = 'test'
col_effect = 'conversion'

a,b = df[col_test_control].unique()

df_pval = df.groupby([col_groupby,col_test_control])\
            [col_effect].agg(['size','mean']).unstack(col_test_control)

df_pval.columns = [f'group{a}_size',f'group{b}_size',
                   f'group{a}_mean',f'group{b}_mean']

df_pval['pvalue'] = df.groupby(col_groupby).apply(lambda dfx: get_ttest(
    dfx.loc[dfx[col_test_control] == a, col_effect],
    dfx.loc[dfx[col_test_control] == b, col_effect]))


df_pval.pipe(print)

结果

         test_size  control_size  test_mean  control_mean    pvalue
country                                                            
A                3             3   0.666667      0.666667  1.000000
B                1             1   1.000000      1.000000       NaN
C                4             3   0.750000      1.000000  0.391002

测试结果

# test for country C
c0 = df.loc[(df.country=='C') & (df.test==0),'conversion']
c1 = df.loc[(df.country=='C') & (df.test==1),'conversion']

pval = stats.ttest_ind(c0, c1, equal_var=False).pvalue
print(pval) # 0.39100221895577053

【讨论】:

    【解决方案2】:

    pivot 可用于获取所需的数据转换。

    def f(group):
        pvt_table = group.pivot(columns='test', values='conversion')
        return(stats.ttest_ind(pvt_table[0], pvt_table[1],
         equal_var=False, nan_policy='omit').pvalue)
    
    grouped = df.groupby(['country'])['test','conversion']
    grouped.apply(f)
    
    #country
    #A           1
    #B          --
    #C    0.391002
    #dtype: object
    
    

    【讨论】:

      猜你喜欢
      • 2019-07-06
      • 2017-02-16
      相关资源
      最近更新 更多