【问题标题】:pandas complex groupby, count and apply a cappandas complex groupby,计数并应用上限
【发布时间】:2020-05-09 23:35:20
【问题描述】:

示例数据帧

> 0   location_day       payType    Name   ratePay      elapsedSeconds   
> 1   2019-12-10           PRE       Amy    12.25             199 
> 2   2019-12-12           PRE       Amy    12.25               7 
> 3   2019-12-17           PRE       Amy    12.25              68 
> 4   2019-12-17            RP       Amy     8.75              62

对于每一天,求和 elapsedSeconds 并计算总 toPay (elapsedSeconds * ratePay) 的新列,但应用“上限”elapsedSeconds 120。对于只有 1 个 payType 的任何一天,应用上限以便仅使用 120计算“toPay”列。

但是……

另外,groupby payType 这样如果一天有 2 个唯一的“payTypes”,则将 elapsedSeconds 相加以确定它是否超过上限 (120),如果是,则从最后一个 payType 中减去 elapsedSeconds 以得出总和等于 120。

所以我想要这个输出:

> 0   location_day       payType    Name   ratePay      elapsedSeconds  
> 1   2019-12-10           PRE       Amy    12.25             120    
> 2   2019-12-12           PRE       Amy    12.25               7  
> 3   2019-12-17           PRE       Amy    12.25              68  
> 4   2019-12-17            RP       Amy     8.75              52

我不太确定如何处理这个问题,实际上只执行了一些非常基本的分组和测试,使用条件语句计算新列,例如

finDfcalc1 = finDf.sort('location_day').groupby(flds)['elapsedSeconds'].sum().reset_index()
finDfcalc1.loc[finDfcalc1['elapsedSeconds'] < 120, 'elapsedSecondsOverage'] = finDfcalc1['elapsedSeconds'] * 1
finDfcalc1.loc[finDfcalc1['elapsedSeconds'] > 120, 'elapsedSecondsOverage'] = finDfcalc1['elapsedSeconds'] - 120
finDfcalc1['toPay'] = finDfcalc1['ratePay'] * finDfcalc1['elapsedSecondsOverage']

所有这些都不必是单行的,只要弄清楚逻辑就会非常高兴。非常感谢所有建议和想法。

【问题讨论】:

    标签: pandas pandas-groupby


    【解决方案1】:

    我们需要在当天进行分组,计算'elapsedSeconds' 的累积和,然后应用一些逻辑将一天中的总数剪裁为 120 秒,然后再计算所有行的正确秒数。

    这里有一个较长的示例数据集,显示了它在多行需要更改的情况下的行为。

    location_day       payType    Name   ratePay      elapsedSeconds   
    2019-12-10           PRE       Amy    12.25             199 
    2019-12-12           PRE       Amy    12.25               7 
    2019-12-17           PRE       Amy    12.25              68 
    2019-12-17            RP       Amy     8.75              62
    2019-12-18           PRE       Amy    12.25              50 
    2019-12-18            RP       Amy     8.75              60
    2019-12-18            RA       Amy     8.75              20
    2019-12-18            RE       Amy     8.75              10
    2019-12-18            XX       Amy     8.75              123 
    

    代码:

    # Will become the seconds you want in the end
    df['real_sec'] = df.groupby('location_day').elapsedSeconds.cumsum()
    
    # Calculate a difference
    m = df['real_sec'] - df['elapsedSeconds']
    
                                          #MagicNum
    df['real_sec'] = (df['real_sec'].clip(upper=120)   # 120 at most
                      - m.where(m.gt(0)).fillna(0)     # only change rows where diff is positive
                     ).clip(lower=0)                   # Negative results -> 0 
    

     location_day payType Name  ratePay  elapsedSeconds  real_sec
    0   2019-12-10     PRE  Amy    12.25             199     120.0
    1   2019-12-12     PRE  Amy    12.25               7       7.0
    2   2019-12-17     PRE  Amy    12.25              68      68.0
    3   2019-12-17      RP  Amy     8.75              62      52.0
    4   2019-12-18     PRE  Amy    12.25              50      50.0
    5   2019-12-18      RP  Amy     8.75              60      60.0
    6   2019-12-18      RA  Amy     8.75              20      10.0
    7   2019-12-18      RE  Amy     8.75              10       0.0
    8   2019-12-18      XX  Amy     8.75             123       0.0
    

    【讨论】:

    • 可能还有其他方法,这很棘手。我认为这个逻辑有效,但还没有完全考虑所有的测试用例。像这样好的单元测试总是最好的。我添加了一个明显丢失的案例,但没有考虑是否还有其他案例。
    • 我很欣赏这一点,这就是我刚开始所需要的,即使这不是完全正确的逻辑。这是我目前非常需要的。谢谢,我会尽快跟进或尽快标记正确。
    猜你喜欢
    • 2021-09-27
    • 2023-01-30
    • 2017-12-19
    • 2018-10-31
    • 1970-01-01
    • 2013-07-14
    • 1970-01-01
    • 2018-05-09
    相关资源
    最近更新 更多