Pandas按条件分组并计算项目数量

4

I have a dataframe like this:

df_test = pd.DataFrame({'ID1':['A','A','A','A','A','A','B','B','B','B'],
                       'ID2':['a','a','a','aa','aaa','aaa','b','b','bb','bb'],
                       'ID3':['c1','c2','c3','c4','c5','c6','c7','c8','c9','c10'],
                       'condition':['','!','','!','','','!','','','!']})

df_test

我希望按ID1将它们分组。结果数据框应该像这样(count_condition表示每个ID2组中'!'的数量):

df_test_result = pd.DataFrame({'ID1':['A','A','A','B','B'],
                       'ID2':['a','aa','aaa','b','bb'],
                        'Count_ID2':[3,1,2,2,2],
                        'Count_ID3':[3,1,2,2,2],
                        'Count_condition': [1,1,0,1,1]})

df_test_result

我尝试使用groupby和agg来获得这个结果,但我无法获取每个组中'!'的数量。这是我的命令:

df_test_result = df_test.groupby(['ID1','ID2']).agg({'ID2':'count','ID3':'nunique','condition':'count'})

如果有一种像这样错误的命令:

df_test = df_test.groupby(['ID1','ID2']).agg({'ID2':'count','ID3':'nunique','condition' == '!':'count'})
4个回答

6
您可以使用命名的groupby
df_test.groupby(
    ['ID1','ID2']).agg(
    Count_ID2=('ID2', 'count'),
    Count_ID3=('ID3', 'count'),
    Count_condition=("condition", lambda x: str(x).count('!')))

输出:

         Count_ID2  Count_ID3  Count_condition
ID1 ID2                                       
A   a            3          3                1
    aa           1          1                1
    aaa          2          2                0
B   b            2          2                1
    bb           2          2                1

在上面的代码中,我们使用aggfunc="count"计算"ID2"和"ID3"列出现的次数,并创建一个小的自定义函数来计算"condition"列中 ! 的出现次数。我们对每个组执行前面提到的操作,为我们的聚合结果返回命名列。

2
请注意,您不需要使用 pd.NamedAgg,您可以使用元组:Count_ID2=('ID2', 'count') 等等。;) - mozway
谢谢,所有的答案都有不同的角度。真的很有帮助!附言:我已经点赞了。 - Jiao
正好是我需要的。谢谢。 - undefined

1

你最初尝试的变体:

(df_test.groupby(['ID1','ID2'])
        .agg({'ID2':'count',
              'ID3':'nunique',
              'condition': lambda s: s.eq('!').sum()})
        .add_prefix('Count_')
        .reset_index()
)

输出:

  ID1  ID2  Count_ID2  Count_ID3  Count_condition
0   A    a          3          3                1
1   A   aa          1          1                1
2   A  aaa          2          2                0
3   B    b          2          2                1
4   B   bb          2          2                1

1
您可以在聚合之前,将空值替换为np.nanpd.NA,然后使用count函数来计算Count_condition列的值:
df_test_result = (
    df_test.replace({'condition': {'': pd.NA}}).groupby(['ID1', 'ID2'])
           .agg({'ID2': 'count','ID3': 'nunique','condition': 'count'})
           .add_prefix('Count_').reset_index()
)

输出:

>>> df_test_result
  ID1  ID2  Count_ID2  Count_ID3  Count_condition
0   A    a          3          3                1
1   A   aa          1          1                1
2   A  aaa          2          2                0
3   B    b          2          2                1
4   B   bb          2          2                1

更新

另一个解决方案是将您的初始condition列转换为布尔值,并使用sum计算值:

df_test_result = (
    df_test.astype({'condition': bool}).groupby(['ID1', 'ID2'])
           .agg({'ID2': 'count','ID3': 'nunique','condition': 'sum'})
           .add_prefix('Count_').reset_index()
)

那么,当它是NaN时就不计算了吗?学到了。 - Jiao
是的。文档中说:“返回系列中非NA/null观测值的数量。” - Corralien

1

@sophocles的回答已经足够了,这个方法使用了相同的思路(命名聚合),但是在聚合之前预先计算了二进制数(应该会更快):

(pd.get_dummies(df_test, columns=['condition'])
   .drop(columns='condition_')
   .groupby(['ID1', 'ID2'])
   .agg(count_ID1=('ID2', 'size'), 
        count_ID2=('ID3', 'size'), 
        count_condition=('condition_!', 'sum'))
)
         count_ID1  count_ID2  count_condition
ID1 ID2
A   a            3          3                1
    aa           1          1                1
    aaa          2          2                0
B   b            2          2                1
    bb           2          2                1

请注意,命名聚合不一定更快;它们提供了重命名聚合列的方便。

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