使用另一个一位编码/重叠掩码的DataFrame进行Pandas GroupBy

4
我有两个数据框,行上有观测值,列上有特征(或组成员),例如:
> data_df

     a    b    c
A    1    2    1
B    0    1    3
C    0    0    1
D    2    1    1
E    1    1    1

> mask_df

    g1   g2
A    0    1
B    1    0
C    1    0
D    1    0
E    0    1

我想根据第二个数据框(mask_df)中的二进制值(掩码),对第一个数据框(data_df)中的值进行分组和聚合(求和)。结果应该是以下内容(按组和特征排序):
> aggr_df

     a    b    c
g1   2    2    5
g2   2    3    2

在pandas中,是否有一种方法可以使用第二个数据框(mask_df)中包含的掩码来对第一个数据框(data_df)进行分组并在单个命令中完成?
5个回答

3
请注意,即使第一个数据框(data_df)中的观测值属于第二个数据框(mask_df)中的多个掩码,此方法仍将起作用。
> pd.concat({x:data_df.mul(mask_df[x],0).sum() for x in mask_df}).unstack()

    a  b  c
g1  2  2  5
g2  2  3  2

这更为通用。 - gc5
然而,这非常慢。在求和/均值聚合的情况下,请参阅我的答案以获得更快的解决方案。 - gc5

3
你可以使用 dotgroupby 廉价地完成此操作:
data_df.groupby(mask_df.dot(mask_df.columns)).sum()

    a  b  c
g1  2  2  5
g2  2  3  2

Where,

mask_df.dot(mask_df.columns)

A    g2
B    g1
C    g1
D    g1
E    g2
dtype: object

假设每一行只有一个列被设置为1,那么这个方法可以很好地运作。

我以为点运算符是用于矩阵乘法的,但我很难理解它如何产生所需的结果。(这可能是因为我不理解它在底层是如何工作的。) - Polkaguy6000
1
@Polkaguy6000 pandas的“点”功能已经扩展到与字符串一起使用,以执行像这样的酷操作。 - cs95
1
mask_df 是一个布尔值的数据框时,它似乎也能工作。 - gc5
1
不幸的是,这个(虽然快速)解决方案只适用于非重叠掩码,请参见W-B或我的答案以获得更一般的解决方案(在求和/平均聚合的情况下)。 - gc5
1
@gc5 很好,谢谢你指出这个区别。我已经给你的回答点赞了。 - cs95

2

最好的方法是将数据框合并。您可以先使用联接语句在索引上进行组合。df_merge = data_df.merge(aggr_df, left_on=True, right_on=True)。然后,您只需使用df_merge进行分组操作。


2
我决定写另一个答案,因为:
  • coldspeed的答案仅适用于one-hot编码
  • W-B的答案无法轻松并行化,因为它运行在字典理解上

在我的情况下,我注意到我可以通过使用mask_dfdata_df的点积来实现相同的结果:

> mask_df.T.dot(data_df)

在只计算均值而不是求和的特殊情况下,可以通过将mask_df按每个组中的1的数量进行缩放来实现:
> mask_df.T.dot(data_df).div(mask_df.sum(), axis=0)

1
这是一种使用列表推导的方法:

pd.DataFrame([(data_df.T * mask_df[i]).sum(axis=1) for i in mask_df.columns], 
             index = mask.columns)

    a  b  c
g1  2  2  5
g2  2  3  2

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