【问题标题】:Aggregate multiple columns in a dataframe based on custom functions基于自定义函数聚合数据框中的多个列
【发布时间】:2018-03-14 08:04:38
【问题描述】:

下午,

我一直在尝试解决这个问题,任何帮助将不胜感激。

这是我的数据框:

Channel state       rfq_qty
A        Done       10
B        Tied Done  10
C        Done       10
C        Done       10
C        Done       10
C        Tied Done  10
B        Done       10
B        Done       10

我想:

  1. 按频道分组,然后状态
  2. 对每个通道的 rfq_qty 求和
  3. 计算状态中每个“完成”字符串的出现次数(“完成”被视为与“已完成”相同,即其中包含“完成”的任何内容)
  4. 将通道 rfq_qty 显示为 rfq_qty (80) 总数的百分比
Channel state   rfq_qty Percentage
A         1       10    0.125
B         3       30    0.375
C         4       40    0.5

我尝试了以下方法:

df_Done = df[
                (
                    df['state']=='Done'
                ) 
                | 
                (
                    df['state'] == 'Tied Done'
                )
            ][['Channel','state','rfq_qty']]

df_Done['Percentage_Qty']= df_Done['rfq_qty']/df_Done['rfq_qty'].sum()
df_Done['Done_Trades']= df_Done['state'].count()

display(
        df_Done[
                (df_Done['Channel'] != 0)
               ].groupby(['Channel'])['Channel','Count of Done','rfq_qty','Percentage_Qty'].sum().sort_values(['rfq_qty'], ascending=False)
       )

有效,但看起来很复杂。有什么改进吗?

【问题讨论】:

    标签: python pandas dataframe group-by summary


    【解决方案1】:

    我认为你可以使用:

    • 首先按isinloc 过滤
    • groupby 并由 agg 聚合,包含新列名称和函数的元组
    • 添加Percentage 除以divsum
    • 如有必要,最后sort_values rfq_qty

    df_Done = df.loc[df['state'].isin(['Done', 'Tied Done']), ['Channel','state','rfq_qty']]
    
    #if want filter all values contains Done
    #df_Done = df[df['state'].str.contains('Done')]
    
    #if necessary filter out Channel == 0
    #mask = (df['Channel'] != 0) & df['state'].isin(['Done', 'Tied Done'])
    #df_Done = df.loc[mask, ['Channel','state','rfq_qty']]
    
    d = {('rfq_qty', 'sum'), ('Done_Trades','size')}
    df = df_Done.groupby('Channel')['rfq_qty'].agg(d).reset_index()
    df['Percentage'] = df['rfq_qty'].div(df['rfq_qty'].sum())
    df = df.sort_values('rfq_qty')
    print (df)
      Channel  Done_Trades  rfq_qty  Percentage
    0       A            1       10       0.125
    1       B            3       30       0.375
    2       C            4       40       0.500
    

    【讨论】:

    • 嘿杰兹瑞尔。感谢那。当我尝试在 sum 列上进行排序时,它无法从最大到最小排序。 df.sort_values(['sum'], ascending=False)
    • @PeterLucas - 只需删除 , ascending=False
    • 完美,列标题上的案例问题。再次感谢!
    • @jpp - 嗯,在我看来,如果 OP 先使用过滤,然后使用过滤后的df_Done DataFrame,那就没问题了。
    • @jpp - 我同意,所以添加了评论df_Done = df[df['state'].str.contains('Done')]
    【解决方案2】:

    一种方法是使用单个 df.groupby.agg 并重命名列:

    import pandas as pd
    
    df = pd.DataFrame({'Channel': ['A', 'B', 'C', 'C', 'C', 'C', 'B', 'B'],
                       'state': ['Done', 'Tied Done', 'Done', 'Done', 'Done', 'Tied Done', 'Done', 'Done'],
                       'rfq_qty': [10, 10, 10, 10, 10, 10, 10, 10]})
    
    agg_funcs = {'state': lambda x: x[x.str.contains('Done')].count(),
                 'rfq_qty': ['sum', lambda x: x.sum() / df['rfq_qty'].sum()]}
    
    res = df.groupby('Channel').agg(agg_funcs).reset_index()
    res.columns = ['Channel', 'state', 'rfq_qty', 'Percentage']
    
    #   Channel  state  rfq_qty  Percentage
    # 0       A      1       10       0.125
    # 1       B      3       30       0.375
    # 2       C      4       40       0.500
    

    这不是最有效的方式,因为它依赖于非矢量化聚合,但如果它对您的用例表现出色,它可能是一个不错的选择。

    【讨论】:

      猜你喜欢
      • 2019-02-08
      • 2023-04-01
      • 1970-01-01
      • 2016-10-10
      • 1970-01-01
      • 2016-05-10
      • 2017-05-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多