Pandas:聚合多个函数并将其应用于同一列

Pandas: Aggregating and applying multiple functions to same column

我有一个 pandas DataFrame 这样的:

n = 6000
my_data = DataFrame ({
    "Category"  : np.random.choice (['cat1','cat2'], size=n) ,
    "val_1"     : np.random.randn(n) ,
    "val_2"     : [i for i in range (1,n+1)]
})

我想计算一列的计数和另外两列的平均值,按 Category 聚合。这在 pandas 文档中描述为 "Applying different functions to DataFrame columns",我是这样做的:

counts_and_means = \
    my_data.groupby("Category").agg (
        {
            "Category"  : np.count_nonzero ,
            "val_1"     : np.mean ,
            "val_2"     : np.mean
        }
    )

我还想计算 val_2 的 t 检验 p 变量,检验 val_2 的均值为零的假设。如果 val_2 是我在整个过程中做任何事情的唯一专栏,我可以只做 Pandas 文档中描述的 "Applying multiple functions at once." 但是,我正在尝试两者都做多列和多个功能。当它只是 "multiple functions at once" 情况时,我可以明确命名输出列,但当涉及多个列时,我无法弄清楚如何去做。现在,当我尝试在一个 agg(...) 步骤中完成所有操作时,val_2 p 值列定义覆盖了原始均值列定义,因为它们都在同一个 dict 中。所以,我最终需要创建第二个 DataFrame 并加入他们:

val_tests = \
    my_data.groupby("Category").agg (
        {
            "val_2"     : lambda arr : sp.stats.ttest_1samp(arr, popmean=0)[1]
        }
    ) \
    .rename (columns={"val_2" : "p_val_2"})

results = pd.merge(counts_and_means, val_tests, left_index=True, right_index=True)

我的问题:有没有什么方法可以在一个 agg(...) 步骤中完成所有这些操作,而不必创建第二个结果 DataFrame 并执行 merge

(参见我的另一个密切相关的 agg 问题 。)

你可以试试这个。我正在传递 val_2

的函数列表
def ttest(arr):     
    return stats.ttest_1samp(arr, popmean=0)[1]

counts_and_means = \
    my_data.groupby("Category").agg (
        {
            "Category"  : np.count_nonzero ,
            "val_1"     : np.mean ,
            "val_2"     : [np.mean,ttest]
        }
    )

如果你喜欢稍微短一点的版本

counts_and_means = \
    my_data.groupby("Category").agg (
        {
            "Category"  : np.count_nonzero ,
            "val_1"     : np.mean ,
            "val_2"     : [np.mean,lambda arr : stats.ttest_1samp(arr, popmean=0)[1]]
        }
    )

这会产生

     Category      val_1            val_2
         count_nonzero  mean        mean    ttest
Category                
cat1     3059           0.007861    2990.997712 0
cat2     2941          -0.007450    3010.383543 0

根据您在下方的评论,您可以"flatten"您的专栏

你可以降低一个级别

counts_and_means.columns = counts_and_means.columns.droplevel()
counts_and_means

但这会删除顶层,留下重复的列名

           count_nonzero    mean        mean       ttest
Category                
cat1       3059             0.007861    2990.997712 0
cat2       2941            -0.007450    3010.383543 0

这可能是更好的选择。它使用列表 comp 来连接我从 here

获得的列名
counts_and_means.columns = ['%s%s' % (a, '_%s' % b if b else '') 
                           for a, b in counts_and_means.columns]
counts_and_means

            Category_count_nonzero  val_1_mean  val_2_mean   val_2_ttest
Category                
cat1        3059                    0.007861    2990.997712  0
cat2         2941                  -0.007450    3010.383543  0