在Python中,针对多个条件下的多列数据进行分组求和和计数

6

I have a pandas dataframe that looks like this:

import pandas as pd
import numpy as np
data = {
    "Type": ["A", "A", "B", "B", "B"],
    "Project": ["X123", "X123", "X21", "L31", "L31"],
    "Number": [100, 300, 100, 200, 500],
    "Status": ['Y', 'Y', 'N', 'Y', 'N']
}
df = pd.DataFrame.from_dict(data)

我希望按照Type进行分组,根据多个条件获取计数和总和,并得到以下结果:

Type  Total_Count  Total_Number  Count_Status=Y  Number_Status=Y  Count_Status=N  Number_Status=N 
 A        2          400              2               400              0               0
 B        5          800              1               200              2              600

我尝试了以下方法,但并不完全符合我的需求。请分享您可能有的任何想法。谢谢!

df1 = pd.pivot_table(df, index = 'Type', values = 'Number', aggfunc = np.sum)
df2 = pd.pivot_table(df, index = 'Type', values = 'Project', aggfunc = 'count')
pd.concat([df1, df2], axis=1)
5个回答

11

如果您想创建一个函数:

def my_agg(x):
    names = {
        'Total_Count': x['Type'].count(),
        'Total_Number': x['Number'].sum(),
        'Count_Status=Y': x[x['Status']=='Y']['Type'].count(),
        'Number_Status=Y': x[x['Status']=='Y']['Number'].sum(),
        'Count_Status=N': x[x['Status']=='N']['Type'].count(),
        'Number_Status=N': x[x['Status']=='N']['Number'].sum()}

    return pd.Series(names)

df.groupby('Type').apply(my_agg)

    Total_Count   Total_Number  Count_Status=Y  Number_Status=Y Count_Status=N  Number_Status=N
Type                        
A      2           400                2                400            0             0
B      3           800                1                200            2            600

4

pivot_table 开始:

pv = (df.pivot_table(index='Type', 
                     columns='Status', 
                     values='Number', 
                     aggfunc='sum')
        .add_prefix('Number_Status='))

print(pv)
Status  Number_Status=N  Number_Status=Y
Type                                    
A                   NaN            400.0
B                 600.0            200.0

接下来,使用groupby
totals = df.groupby('Type').Number.agg([
    ('Total_Count', 'count'),  ('Total_Number', 'sum')])

print(totals)
      Total_Count  Total_Number
Type                           
A               2           400
B               3           800

最后,使用 OHE 进行状态计数:

cnts = (df.set_index('Type').Status
          .str.get_dummies()
          .sum(level=0)
          .add_prefix('Count_Status='))

      Count_Status=N  Count_Status=Y
Type                                
A                  0               2
B                  2               1

将所有内容整合起来:
pd.concat([pv, totals, cnts], axis=1).sort_index(axis=1)

      Count_Status=N  Count_Status=Y  Number_Status=N  Number_Status=Y  \
Type                                                                                             
A                  0               2              NaN            400.0            
B                  2               1            600.0            200.0            

Total_Count  Total_Number
          2           400
          3           800

2

处理方式

s1 = df.groupby('Type').Number.agg(['count', 'sum'])
s2 = df.groupby(['Type', 'Status']).Number.agg(['count', 'sum']).unstack(fill_value=0).sort_index(level=1, axis=1)
s2.columns = s2.columns.map('_Status='.join)
s1 = s1.add_prefix('Total_')
s = pd.concat([s1, s2], axis=1)
s
      Total_count  Total_sum  count_Status=N  sum_Status=N  count_Status=Y  \
Type                                                                         
A               2        400               0             0               2   
B               3        800               2           600               1   
      sum_Status=Y  
Type                
A              400  
B              200  

2
你可以使用pd.pivot_tablemargins参数。在最后删除列总计,因为你只需要按行方向进行汇总。
import pandas as pd

df1 = df.pivot_table(index='Type', columns='Status', values='Number', 
                     aggfunc=['sum', 'count'], 
                     margins=True, 
                     margins_name='Total').fillna(0).drop('Total')
#          sum              count           
#Status      N      Y Total     N    Y Total
#Type                                       
#A         0.0  400.0   400   0.0  2.0     2
#B       600.0  200.0   800   2.0  1.0     3

如果需要,可以重命名列:

d = {'Y': 'Status=Y', 'N': 'Status=N', 'Total': 'Total'}
df1.columns = [f'{x}_{d.get(y)}' for x,y in df1.columns]

输出 df1

      sum_Status=N  sum_Status=Y  sum_Total  count_Status=N  count_Status=Y  count_Total
Type                                                                                    
A              0.0         400.0        400             0.0             2.0            2
B            600.0         200.0        800             2.0             1.0            3

1
你可以使用 pandas.core.groupby.GroupBy.apply 来完成这个任务。例如,你可以编写一个函数,在获取 Groupby 对象后对每一列的数据进行处理。
def compute_metrics(x):
    result = {'Total_Number': x['Number'].sum(), 'Count_Status=Y': len(x['Status'] == "Y")}
    return pd.Series(result)

然后,df.groupby('Type').apply(compute_metrics)将返回以下类似的数据框:
Type  Total Number Count_Status=Y
A     400          2             
B     800          3

希望这对你有所帮助。

祝好。


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