Pandas: 从第二行开始。用前一行的值减去当前行的值,并将其作为下一个减法的值。

4

背景

我需要使用Pandas编写一个算法,从第二行开始,将一列值减去上一行的值,并使用结果继续减去下一行的值,以此类推。

示例

INPUT:
ID    VALUE
0       1
1       10
2       30
3       45
4       78

OUTPUT (just the result, not the operation itself):
ID    VALUE
0       1
1       9  #(10-1)
2       21 #(30-9)
3       24 #(45-21)
4       54 #(78-24)

我所尝试的

df['VALUE'] = df['VALUE'] - df['VALUE]'.shift() # Doesn't starts with the second row, and use the original dataframe to subtract

df['VALUE'] = df['VALUE'].diff() # Doesn't starts with the second row, and use the original dataframe to subtract
3个回答

9

Numpy, cumsum 循环求和并交替改变符号

i = np.arange(len(df))
j = np.arange(2)

a = np.where(
    (i[:, None] + j) % 2 == 0, 1, -1
) * df.VALUE.values[:, None]

b = a.cumsum(0)[i, i % 2]

df.assign(VALUE=b)

   ID  VALUE
0   0      1
1   1      9
2   2     21
3   3     24
4   4     54

说明

首先要注意的是

X0 ->                     X0
X1 ->                X1 - X0
X2 ->           X2 - X1 + X0
X3 ->      X3 - X2 + X1 - X0
X4 -> X4 - X3 + X2 - X1 + X0

所以我想把每一行交替乘以负一……但是对于另一种选择的交替行,我需要这样做两次。

我需要生成一个掩码,在两个选项之间交替使用 +1 和 -1。

i = np.arange(len(df))
j = np.arange(2)

m = np.where(
    (i[:, None] + j) % 2 == 0, 1, -1
)

m

array([[ 1, -1],
       [-1,  1],
       [ 1, -1],
       [-1,  1],
       [ 1, -1]])

现在,我需要将其广播到我的df.VALUE中。
a = m * df.VALUE.values[:, None]

a

array([[  1,  -1],
       [-10,  10],
       [ 30, -30],
       [-45,  45],
       [ 78, -78]])

注意这种模式。现在我进行cumsum操作。
a.cumsum(0)

array([[  1,  -1],
       [ -9,   9],
       [ 21, -21],
       [-24,  24],
       [ 54, -54]])

但我需要正数……更具体地说,我需要交替的正数。因此,我使用经过修改的arange进行切片。

b = a.cumsum(0)[i, i % 2]
b

array([ 1,  9, 21, 24, 54])

这是我最终分配给现有列的内容。
df.assign(VALUE=b)

   ID  VALUE
0   0      1
1   1      9
2   2     21
3   3     24
4   4     54

这将产生一个df的拷贝,并用b覆盖VALUE列。
如果要保留此答案,请确保重新分配给一个新名称或df
df_new = df.assign(VALUE=b)

哇,我甚至不知道cumsum存在。做得好,非常感谢。我只是不理解df.assign部分... - Lodi
对问题的解释很好,并且通过模式识别进行了详细分解。+1 - Scott Boston
感谢 @ScottBoston (-: - piRSquared

3

很难说是否有一种熊猫的方式来做到这一点,所以我在几个月前就问了这个问题。以下是我的解决方案。

l=[]
for x,y in enumerate(df.VALUE):
    if x ==0: 
       l.append(y)
    else : 
       l.append(y-l[x-1])
l
Out[20]: [1, 9, 21, 24, 54]

我实际上不需要使用pandas的方法/函数。你的解决方案完美地解决了我的问题,但现在我需要将这个列表设置为每一列的VALUE,甚至是一个新的DIFFVALUE列。 - Lodi
1
df['DIFF']=l @Lodi - BENY

1
这应该可以工作:

df = pd.DataFrame({"ID": [0, 1, 2, 3, 4], 
                   "VALUE": [1, 10, 30, 45, 78]})
cumsum_with_parity = df.groupby(df.index % 2).VALUE.cumsum()
df["VALUE"] = cumsum_with_parity - cumsum_with_parity.shift().fillna(0)

很好,使用 groupbycumsum 的解决方案 @Colin。+1 - Scott Boston

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