使用pandas进行一些计算,填充列时使用该列中的先前值。

3
我的数据框看起来像这样:
   scale  cons    hold    supply   add.supply     s_res      z_res
48  -5     NaN    NaN      NaN       NaN           NaN        NaN   
49  -4     NaN    NaN      NaN       NaN           NaN        NaN   
50  -3     NaN    NaN      NaN       NaN           NaN        NaN   
51  -2     NaN    NaN      NaN       NaN           NaN        NaN   
52  -1     NaN    NaN      NaN       NaN           NaN        NaN   
53   0      0     300       0        NaN           100        200   
54   1     20     NaN       0        NaN           200        322   
55   2     30     NaN      70        NaN           100        100   
56   3     25     NaN       0        NaN           400        110   
57   4     15     NaN       0        NaN           100        300   
58   5     10     NaN       0        NaN           100        180   
59   6     40     NaN       0        NaN           100        100   
...

我需要做以下事情:

scale = 1 开始,填充列 hold 的值,计算方法如下:

我取列 hold 中的前一个值,并从中减去来自列 cons 的当前单元格对应值,再加上来自列 supply 的对应值。

(对于列 hold 中对应于 scale = 1 的单元格,它将是 (300 - 20) + 0 = 280, 对于下一个单元格 (280 - 30) + 70) = 320,对于下一个单元格 (320 - 25) + 0) = 295,以此类推)

如果列 hold 中的值小于列 s_res 中的对应值,则在下一个单元格中必须添加列 s_resz_res 中相应下一个单元格值之间的差异。

例如,列 hold 中的值为 295,其中 scale = 3。这个值小于列 s_res = 400 中的值。然后我需要计算下一个值: (295 - 15) + 0 + (300 - 100) = 480。并将此差异写入列 add.supply

我需要检查列 hold 中的每个新计算值是否小于列 s_res 中的值。

结果应该像这样:

   scale  cons    hold    supply   add.supply     s_res      z_res
48  -5     NaN    NaN      NaN       NaN           NaN        NaN   
49  -4     NaN    NaN      NaN       NaN           NaN        NaN   
50  -3     NaN    NaN      NaN       NaN           NaN        NaN   
51  -2     NaN    NaN      NaN       NaN           NaN        NaN   
52  -1     NaN    NaN      NaN       NaN           NaN        NaN   
53   0      0     300       0        NaN           100        200   
54   1     20     280       0        NaN           200        322   
55   2     30     320      70        NaN           100        100   
56   3     25     295       0        NaN           400        110   
57   4     15     480       0        200           100        300   
58   5     10     470       0        NaN           100        180   
59   6     40     430       0        NaN           100        100   
...

我将非常感谢您提供任何关于IT技术的建议。 更新 我尝试应用代码。
df['hold'] = df.hold.fillna(method='ffill') - df.cons.cumsum() + df.supply.cumsum()
df['add.supply'] = np.where(df.hold.shift() < df.s_res.shift(), df.z_res - df.s_res, np.nan)
df['hold'] = df.hold + df['add.supply'].fillna(0).cumsum()

我正在尝试将数据框扩展到更大的规模,但遇到了问题。

我的新数据框

   scale   cons   hold  supply  add.supply   s_res   z_res
 0   0       0    300     0        NaN        100     200
 1   1      20    NaN     0        NaN        200     322
 2   2      30    NaN    70        NaN        100     100
 3   3      25    NaN     0        NaN        400     110
 4   4      15    NaN     0        NaN        100     300
 5   5      10    NaN     0        NaN        100     180
 6   6      40    NaN     0        NaN        100     100
 7   7      60    NaN     0        NaN        300     400
 8   8      50    NaN     0        NaN        245     300
 9   9      70    NaN     0        NaN        300     600
10  10      50    NaN     0        NaN        143     228
...

结果应该如下所示:
   scale   cons   hold  supply  add.supply   s_res   z_res
 0   0       0    300     0        NaN        100     200
 1   1      20    280     0        NaN        200     322
 2   2      30    320    70        NaN        100     100
 3   3      25    295     0        NaN        400     110
 4   4      15    480     0        200        100     300
 5   5      10    470     0        NaN        100     180
 6   6      40    430     0        NaN        100     100
 7   7      60    370     0        NaN        300     400
 8   8      50    320     0        NaN        245     300
 9   9      70    250     0        NaN        300     600
10  10      50    285     0         85        143     228
...

但是代码执行的结果并不是预期的:
   scale   cons   hold  supply  add.supply   s_res   z_res
 0   0       0    300     0        NaN        100     200
 1   1      20    280     0        NaN        200     322
 2   2      30    320    70        NaN        100     100
 3   3      25    295     0        NaN        400     110
 4   4      15    480     0        200        100     300
 5   5      10    470     0        NaN        100     180
 6   6      40    430     0        NaN        100     100
 7   7      60    370     0        NaN        300     400
 8   8      50    375     0         55        245     300
 9   9      70    605     0        300        300     600
10  10      50    640     0         85        143     228
...

hold = 370之后出现了错误,但我不明白原因。


1
你能解释一下你到目前为止尝试了什么吗?这能帮助人们找到他们最有用的解释。 - ASGM
@ASGM,非常抱歉,我恐怕没有完全理解您的问题。然而,任务的开头部分会带来最大的困难。我不明白如何在列“hold”中使用先前的值,并同时从其中减去与我当前计算的单元格相对应的列“cons”中的值。无论如何,计算总是从“scale = 1”的位置开始。我尝试使用“shift()”,但没有成功。 - yanadm
1个回答

3

不用逐行操作,您可以使用cumsum()np.where的组合在整个DataFrame上执行此操作:

df['hold'] = df.hold.fillna(method='ffill') - df.cons.cumsum() + df.supply.cumsum()
df['add.supply'] = np.where(df.hold.shift() < df.s_res.shift(), df.z_res - df.s_res, np.nan)
df['hold'] = df.hold + df['add.supply'].fillna(0).cumsum()

考虑将你想要进行的转换分为两个阶段。首先,在初始阶段,您需要从df.hold的初始值中添加和减去一些值。然后,根据某些条件,您会修改该新的hold值。 cumsum()接受一个Series或DataFrame,并创建一个新版本,其中每行都是前面行和当前行的累积总和。您可以对df.consdf.supply执行此操作,以获取将从df.hold中减去和添加的累积金额。现在,您已经计算出了第一阶段的df.hold
您可以使用np.where查找df.hold何时满足您感兴趣的条件。如果满足条件,则可以相应地设置df['add.supply']。然后,您可以将此新列添加到df.hold中。请注意,我们使用fillna(0)确保每行都有一个值,并再次使用cumsum()以随时间保留添加的条件值。
更新:
由于未来的第一阶段的df.hold值尚未包括它,因此上述原始代码在添加一个add.supply值后无法正常工作。可能有一种非迭代的方法来解决这个问题,肯定有一种更好、更清晰的方法来解决下面所做的事情,但至少可以完成任务。
df['hold'] = df.hold.fillna(method='ffill') - df.cons.cumsum() + df.supply.cumsum()

hold = df.hold.tolist()
s_res = df.s_res.tolist()
add = (df.z_res - df.s_res).shift(-1).tolist()

newh = [hold[0]]
totala = 0
for h, s, a in zip(hold, s_res, add):
    newh.append(h + totala)
    if newh[-1] < s:
        totala += a

df['hold'] = pd.Series(newh[1:])
df['add.supply'] = np.where(df.hold.shift() < df.s_res.shift(), df.z_res - df.s_res, np.nan)

谢谢你的回答!你能看一下问题中的更新吗?我对结果有些困惑。 - yanadm
@YanaDolyuk 我看到了问题,正在想办法解决它。 - ASGM
1
@YanaDolyuk 我提供了一个快速而简单的解决方案来解决这个问题。我相信有更好的方法可以做到这一点 - 但是这个方法可以完成工作。也许你可以优化它! - ASGM
太好了!非常感谢你! - yanadm

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