多列的条件聚合计算

时间:2021-07-23 16:50:18

标签: python pandas

我想用数据框做一些计算

<头>
ID 方法 国家 数量 成功
95 Мир 白俄罗斯 6063 0
96 大师 日本 4013 0
97 美国运通 白俄罗斯 1426 1
98 大师 白俄罗斯 5692 1
99 万事达卡 俄罗斯 6929 1

我想按方法和国家、付款次数、成功率和成功付款总额计算平均金额。

Success Rate = (Number of payments where Success = 1) / All payments

在 SQL 中,我会做到这一点非常简单

    SELECT country,
           method,
           avg(amount),
           count(1),
           count(CASE WHEN success = 1 THEN id END) / count(1) AS conversion, 
sum(CASE WHEN success = 1 THEN amount END) sum_success, 
    FROM data
    GROUP BY country, method;

前两个计算在 Python 中也相对简单。

df.groupby(['Country', 'Method']).agg({'Amount': ['mean', 'count']})

但第三、第四次计算似乎不太可能,不费吹灰之力。

有没有办法快速优雅地做到这一点?

请不要说我可以通过采用 Success 列的 mean() 来计算成功率。我知道。我已经简化了我实际要做的事情,我的真正任务无法通过这种方式解决。

2 个答案:

答案 0 :(得分:3)

SQL 可以在返回结果之前解析您的语句(它甚至可以找出列名,即使它们是大写或小写的)- 只要您使用正确的关键字,SQL 就可以轻松实现这种方式;在 Pandas 中,通常情况下,您必须明确;在这种情况下,您必须在聚合之前预先创建一些列 - 通常情况下,这样做会更快:

           # create the columns that will be needed    
(df.assign(sum_success = lambda df: df.Amount.where(df.Success==1), 
           conversion = lambda df:df.Success.eq(1))
   .groupby(['Country', 'Method'])
   .agg(Amount=('Amount', 'mean'), 
        count=('Amount', 'size'), 
        conversion=('conversion', 'sum'),
        sum_success = ('sum_success', 'sum'))
  .reset_index() # indexes are useful, so you may not reset ... it depends
   )
 
   Country            Method  Amount  count  conversion  sum_success
0  Belarus  American Express  1426.0      1           1       1426.0
1  Belarus           Maestro  5692.0      1           1       5692.0
2  Belarus               Мир  6063.0      1           0          0.0
3    Japan           Maestro  4013.0      1           0          0.0
4   Russia        Mastercard  6929.0      1           1       6929.0

注意 conversion,我不必创建条件本身,我只是使用布尔结果并将其汇总到 agg 部分。因此,根据聚合情况,您可能需要使其适应 Pandas 的细微差别。

顺便说一句,Python 中还有另一种数据处理 - datatable,它允许嵌套计算,类似于 SQL。它仍在增长,但不像熊猫那样功能丰富。

答案 1 :(得分:1)

我们可以尝试采用 mean where values eq 的情况(1):

df.groupby(['Country', 'Method']).agg({'Amount': ['mean', 'count'],
                                       'Success': lambda s: s.eq(1).mean()})
                          Amount        Success
                            mean count <lambda>
Country Method                                 
Belarus American Express  1426.0     1      1.0
        Maestro           5692.0     1      1.0
        Мир               6063.0     1      0.0
Japan   Maestro           4013.0     1      0.0
Russia  Mastercard        6929.0     1      1.0

DataFrame 构造函数:

df = pd.DataFrame({
    'ID': [95, 96, 97, 98, 99],
    'Method': ['Мир', 'Maestro', 'American Express', 'Maestro', 'Mastercard'],
    'Country': ['Belarus', 'Japan', 'Belarus', 'Belarus', 'Russia'],
    'Amount': [6063, 4013, 1426, 5692, 6929], 
    'Success': [0, 0, 1, 1, 1]
})