【问题标题】:Cumsum column while skipping rows or setting fixed values on a condition based on the result of the actual cumsum根据实际 cumsum 的结果跳过行或在条件上设置固定值时的 Cumsum 列
【发布时间】:2021-11-07 22:18:30
【问题描述】:

我试图在 pandas 中找到一个矢量化解决方案,这在电子表格中很常见,即在根据实际 cumsum 的结果跳过或设置条件的固定值时进行 cumsum。我有以下内容:

    A
1   0
2  -1
3   2
4   3
5  -2
6  -3
7   1
8  -1
9   1
10 -2
11  1
12  2 
13 -1
14 -2

我需要添加第二列,其 cumsum 为“A”,如果其中一个和为正值,则将其替换为 0,并使用该 0 继续 cumsum。同时,如果 cumsum 给出负值低于 B 列 0 之后记录的 A 列最小值我需要用 A 列中的最低值替换它。我知道这是一个很大的问题,但是有一个矢量化解决方案吗?也许使用辅助列。结果应如下所示:

    A   B
1   0   0
2  -1  -1  # -1+0 = -1
3   2   0  # -1 + 2 = 1 but  1>0 so this is 0
4   3   0  # same as previous row
5  -2  -2  # -2+0 = -2
6  -3  -3  # -2-3 = -5 but the lowest value in column A since last 0 is -3 so this is replaced by -3
7   1  -2  #  1-3 = -2
8  -1  -3  # -1-2 = -3
9   1  -2  # -3 + 1 = -2
10 -2  -3  # -2-2 = -4 but the lowest value in column A since last 0 is -3 so this is replaced by -3 
11  1  -2  # -3 +1 = -2
12  2   0  # -2+2 = 0
13 -1  -1  # 0-1 = -1
14 -2  -2  # -1-2 = -3 but the lowest value in column A since last cap is -2 so this is -2 instead of -3

目前我做了这个,但不能 100% 工作,而且效率也不高:

df['B'] = 0
df['B'][0] = 0
for x in range(len(df)-1):
    A = df['A'][x + 1]
    B = df['B'][x] + A
    if B >= 0:
        df['B'][x+1] = 0
    elif B < 0 and A < 0 and B < A:
        df['B'][x+1] = A
    else:
        df['B'][x + 1] = B

【问题讨论】:

  • 你如何从 B 列获取值?,我正在尝试使用 pd.Series([0, -1, 2, 3, -2, -3, 1, -1, 1, -2, 1, 2, -1, -2]).cumsum() 并且它正在返回这个数组 [0, -1, 1, 4, 2, -1, 0, -1, 0, -2, -1, 1, 0, -2] 我可以使用这个累积总和并执行必要的操作来获取你的当前值B 列。但我不知道如何获得[Nan, -1, 0, 0, -2, -3, -2, -3, -2, -3, -2, 0, -1, -2]
  • B 列是我需要的实际结果。 cumsum 无法到达 B 列,因为我需要在 cumsum 上应用条件才能获取 B 列。我将编辑我的问题,以便更清楚。
  • 您可以使用df['A'].expanding(1).apply(function) 运行自己的function 将得到:第一行,接下来的2行,接下来的3行等。这样我几乎可以得到结果,但仍然有问题检查自上次 0 以来的最低值。
  • 我对最小值有疑问,如果我们连续替换它,或者我们只将它从之前分配的值中取到 B 例如min = min or B [i-1]
  • 所以最小值是从 A 列获得的,并且每次 A 列给出较低的值时都会更新,然后在 B = 0 时重置。

标签: python pandas numpy cumsum


【解决方案1】:

使用df['A'].expanding(1).apply(function)我可以运行自己的function,它首先只得到一行、接下来的2行、接下来的3行等。我没有给出之前计算的结果,它需要一次又一次地进行所有计算但它不需要global 变量和硬编码df['A']

文档:Series.expanding

A = [0, -1, 2, 3, -2, -3, 1, -1, 1, -2, 1, 2, -1, -2]

import pandas as pd

df = pd.DataFrame({"A": A})

def function(values):
    #print(values)
    #print(type(valuse)
    #print(len(values))

    result = 0

    last_zero = 0

    for index, value in enumerate(values):
        result += value

        if result >= 0:
            result = 0
            last_zero = index
        else:
            minimal = min(values[last_zero:])
            #print(index, last_zero, minimal)
                        
            #if result < minimal:
            #   result = minimal
            result = max(result, minimal)
            
    #print('result:', result)
    return result

df['B'] = df['A'].expanding(1).apply(function)

df['B'] = df['B'].astype(int)

print(df)

结果:

    A  B
0   0  0
1  -1 -1
2   2  0
3   3  0
4  -2 -2
5  -3 -3
6   1 -2
7  -1 -3
8   1 -2
9  -2 -3
10  1 -2
11  2  0
12 -1 -1
13 -2 -2

相同但使用普通apply() - 它需要global 变量和硬编码df['A']

A = [0, -1, 2, 3, -2, -3, 1, -1, 1, -2, 1, 2, -1, -2]

import pandas as pd

df = pd.DataFrame({"A": A})

result = 0
last_zero = 0
index = 0

def function(value):
    global result
    global last_zero
    global index
    
    result += value

    if result >= 0:
        result = 0
        last_zero = index
    else:        
        minimal = min(df['A'][last_zero:])
        #print(index, last_zero, minimal)
                        
        #if result < minimal:
        #   result = minimal
        result = max(result, minimal)
       
    index += 1
    
    #print('result:', result)
    return result

df['B'] = df['A'].apply(function)
df['B'] = df['B'].astype(int)

print(df)

同样使用普通的for-loop

A = [0, -1, 2, 3, -2, -3, 1, -1, 1, -2, 1, 2, -1, -2]

import pandas as pd

df = pd.DataFrame({"A": A})

all_values = []

result = 0
last_zero = 0

for index, value in df['A'].iteritems():
    
    result += value
    
    if result >= 0:
        result = 0
        last_zero = index
    else:    
        minimal = min(df['A'][last_zero:])
        #print(index, last_zero, minimal)
                            
        #if result < minimal:
        #   result = minimal
        result = max(result, minimal)
           
    all_values.append(result)

df['B'] = all_values

print(df)

【讨论】:

  • 我看到你付出了很多努力,我想避免 for 循环和 if 语句以及变量。我在想可能可以创建一个带有 ID 号的哑列来标识零之间的列的每个段,然后使用 groupby 获取最小值以获取最小值。
  • 我也尝试在没有for-loop 的情况下做到这一点,并期望expanding(1).apply() 会像cumsum() 一样工作,但有自己的功能 - 但它不起作用,我找不到东西更好。
猜你喜欢
  • 2018-11-17
  • 1970-01-01
  • 2016-04-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多