Pandas分组和求组总和

6
我有一个Pandas DataFrame,其中包含客户退款原因。它包含以下示例数据行:
    **case_type**       **claim_type**
1   service             service
2   service             service
3   chargeback          service
4   chargeback          local_charges
5   service             supplier_service
6   chargeback          service
7   chargeback          service
8   chargeback          service
9   chargeback          service
10  chargeback          service
11  service             service_not_used
12  service             service_not_used

我想将客户的原因与某种标记的原因进行比较。这没有问题,但我还想看到特定组(客户原因)中的记录总数。
case_claim_type = df[["case_type", "claim_type"]]
case_claim_type.groupby(by=("case_type", "claim_type"))["case_type"].count()

这是我的输出,例如:
**case_type**     **claim_type**                 
service           service                         2
                  supplier_service                1
                  service_not_used                2
chargeback        service                         6
                  local_charges                   1

我还想得到每种案例类型的输出总和。就像这样:
**case_type**     **claim_type**                 
service           service                         2
                  supplier_service                1
                  service_not_used                2
                  total:                          5
chargeback        service                         6
                  local_charges                   1
                  total:                          7

这并不一定非要使用最后的输出格式,每个案例类型的(汇总)总数的列也可以。

你能提供一些样例输入数据吗? - Scott Boston
@ScottBoston 是的,我刚刚添加了一些示例输入数据。 - eppe2000
2个回答

6

您可以使用:

df = case_claim_type.groupby(by=("case_type", "claim_type"))["case_type"].count()
print (df)
case_type   claim_type      
chargeback  local_charges       1
            service             1
service     service             2
            supplier_service    1
Name: case_type, dtype: int64

您可以通过聚合 sum 并使用 MultiIndex.from_tuples 添加 MultiIndex 来创建新的 DataFrame

df1 = df.sum(level=0)
#same as
#df1 = df.groupby(level=0).sum()
new_cols= list(zip(df1.index.get_level_values(0),['total'] * len(df.index)))
df1.index = pd.MultiIndex.from_tuples(new_cols)
print (df1)
chargeback  total    2
service     total    3
Name: case_type, dtype: int64

然后将它们concat在一起,最后sort_index

df2 = pd.concat([df,df1]).sort_index()
print (df2)
case_type   claim_type      
chargeback  local_charges       1
            service             1
            total               2
service     service             2
            supplier_service    1
            total               3
Name: case_type, dtype: int64

谢谢这个解决方案,非常直观易懂。我尝试了一下,效果非常好。然而,我还是选择了其他答案作为最佳解决方案,因为它更加简洁。 - eppe2000
@eppe2000 - 如果你得到了两个好答案,那肯定是很难选择了 ;) 但是使用什么解决方案取决于你 ;) 祝你好运! - jezrael
嘿@jezrael - 我知道这有点过时了,但我正在寻找一个与此类似的答案,但可以对更多内容进行总计,比如平均值。有什么线索吗? - cjcrm
@cjcrm - 然后将 df1 = df.sum(level=0) 更改为 df1 = df.mean(level=0) - jezrael
@jezrael 对的,但是如果我的groupby使用了,比如,groupby(...).agg({'case_type':['sum','mean']},那么获取每个agg函数应用的case_type的正确值的最佳方法是什么? - cjcrm
@cjcrm - 我认为需要进行过滤,并且对于每个数据框使用正确的聚合函数。但也许最好的方法是创建一个带有示例数据和期望输出的问题。 - jezrael

6

其中:

df = pd.DataFrame({'case_type':['Service']*20+['chargeback']*9,'claim_type':['service']*5+['local_charges']*5+['service_not_used']*5+['supplier_service']*5+['service']*8+['local_charges']})

df_out = df.groupby(by=("case_type", "claim_type"))["case_type"].count()

使用 pd.concat、带有 level 参数的 sumassign

(pd.concat([df_out.to_frame(),
           df_out.sum(level=0).to_frame()
                 .assign(claim_type= "total")
                 .set_index('claim_type', append=True)])
  .sort_index())

输出:

                             case_type
case_type  claim_type                 
Service    local_charges             5
           service                   5
           service_not_used          5
           supplier_service          5
           total                    20
chargeback local_charges             1
           service                   8
           total                     9

谢谢。非常优雅的解决方案! - eppe2000

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