【问题标题】:How to group pandas rows whenever a certain cumsum threshold is crossed (restarting the cumsum for each new group)每当超过某个 cumsum 阈值时如何对 pandas 行进行分组(重新启动每个新组的 cumsum)
【发布时间】:2023-03-25 21:10:01
【问题描述】:

每当超过给定的 cumsum 阈值时,我都需要对连续行进行分组的帮助。当超过这个阈值时,cumsum 也应该重新启动(到零),如下所示:

Index  Values       Regular CumSum  Wanted CumSum  Wanted Column
1      0.0666666666    0.0666666666    0.000000    0.0
2      0.0238095238    0.0904761904    0.000000    1.0
3      0.0134146341    0.1038908246    0.000000    2.0
4      0.0210135970    0.1249044216    0.013414    2.0
5      0.0072639225    0.1321683441    0.000000    3.0
6      0.0158536585    0.1480220027    0.007263    3.0
7      0.0012004801    0.1492224829    0.000000    4.0
8      0.0144230769    0.1636455598    0.001200    4.0
9      0.0130331753    0.1766787351    0.015623    4.0

在这种情况下,阈值为 0.02(抱歉所有小数)。

  • 任何大于阈值的条目都应立即形成或关闭一个组(例如索引 1,2 和 4 中的条目)
  • 索引 3 上的条目小于阈值,因此它等待下一个连续条目。如果下一个条目(单独或与索引 3 的值相加)超过阈值,则它们形成一个新组,否则下一个条目也将被包括在内(在这种情况下,索引 4 的条目大于阈值,因此形成一个新组)。
  • 条目 5 小于阈值 0.02,但将条目 6 相加,使其大于 0.02,因此关闭了一个组。
  • 条目 7,8 和 9 加起来大于 0.02,从而形成一个组。
  • ....

我能够开发以下简单的代码来实现这一点,但我希望有人可以帮助我开发一种更快的方法,也许可以利用 pandas 库:

FinalList = [0]
index=0
cumsum = 0
i=1
#while to go through all entries in df
while(i!=df.index[-1]): 
    #When entry is larger(or equal) than threshold immediately close group and clear cumsum
    if df.Values.iloc[i] >= Threshold:
        FinalList.append(index)
        cumsum = 0
        index+=1
    #When entry is smaller than threshold
    if df.Values.iloc[i] < Threshold:
        #If previous cumsum plus current entry surpass threshold group is closed.       
        if cumsum + df.Values.iloc[i] > Threshold:
                FinalList.append(index)
                cumsum=0
                index+=1
            #Otherwise, continue increasing cumsum until it crosses threshold
            else:
                cumsum = cumsum + df.Values.iloc[i]
                FinalList.append(index)
        i+=1

【问题讨论】:

  • stackoverflow.com/questions/54208023/… 似乎它应该解决你的问题,如果性能是一个大问题。
  • 谢谢你,有了这个答案和@P Maschhoff 的答案,执行时间减少到不到一秒!

标签: python pandas algorithm


【解决方案1】:

更多的pandas 方法是遍历数据框或列,如下所示:

threshold = 0.02
cumsum = 0
group = 0
for idx, value in df.Values.iteritems():
    cumsum += value
    df.loc[idx, 'Group'] = group
    if cumsum >= threshold:
        cumsum = 0
        group += 1
         Values  Group
Index                 
1      0.066667    0.0
2      0.023810    1.0
3      0.013415    2.0
4      0.021014    2.0
5      0.007264    3.0
6      0.015854    3.0
7      0.001200    4.0
8      0.014423    4.0
9      0.013033    4.0

这并没有做任何特别花哨的事情,但应该更快,因为它减少了索引操作和一般操作。如果你想了解更多关于如何编写pandas 风格的代码,我推荐this 的一位开发者的博客系列。

【讨论】:

  • 谢谢!这将执行时间减少到大约 5 秒,但我希望将执行时间减少更多,希望减少到毫秒(100 秒是可以接受的)
【解决方案2】:

结合@P Maschoff 和@ALlolz 的答案,我开发了以下代码,其执行时间(使用执行时间超过 15 秒的数据集,使用我最初问题中的代码)减少到一秒以下:

@njit
def dynamic_cumsum(seq, max_value):
    FinalList = [0]
    cumsum = 0
    running = 0
    for i in prange(len(seq)):
        cumsum += seq[i]
        if cumsum >= max_value:
            cumsum = 0
            running += 1        
        FinalList.append(running)
    return FinalList

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-17
    • 2019-11-16
    • 1970-01-01
    • 1970-01-01
    • 2015-02-01
    相关资源
    最近更新 更多