根据递减值计算新值

Jon*_*nts 14 python pandas

问题:

我想做的是逐步减少a中的值,使Series基数持续减少.

我不知道的术语这个-我认为我可以做一些与cumsumdiff,但我觉得我自己领先于白费力气有...

开始代码:

import pandas as pd

ALLOWANCE = 100
values = pd.Series([85, 10, 25, 30])
Run Code Online (Sandbox Code Playgroud)

期望的输出:

desired = pd.Series([0, 0, 20, 30])
Run Code Online (Sandbox Code Playgroud)

理由:

从基数开始ALLOWANCE- 中的每个值Series减少剩余量,以及余量本身,因此执行以下步骤:

  • 从100开始,我们可以完全删除85所以它变成了0,我们现在已经15离开了ALLOWANCE
  • 下一个值是10,我们仍然15可用,所以这又变成0了我们5离开了.
  • 下一个值是25- 我们只剩5下了,所以这就成了20现在我们没有进一步的补贴.
  • 下一个值是30,因为没有余量,值仍为30.

Ale*_*ley 10

继你最初的想法cumsumdiff,你可以写:

>>> (values.cumsum() - ALLOWANCE).clip_lower(0).diff().fillna(0)
0     0
1     0
2    20
3    30
dtype: float64
Run Code Online (Sandbox Code Playgroud)

这是values减去津贴的累计和.负值被剪切为零(因为在我们透支我们的津贴之前我们不关心数字).从那里,您可以计算差异.

但是,如果第一个值可能大于允许值,则首选以下两行变体:

s = (values.cumsum() - ALLOWANCE).clip_lower(0)
desired = s.diff().fillna(s)
Run Code Online (Sandbox Code Playgroud)

这将NaN使用"first value - allowance"值填充第一个值.因此,在ALLOWANCE降低到75 的情况下,它返回desiredSeries([10, 10, 25, 30]).


Car*_*ten 8

你的想法cumsumdiff工作.它看起来并不太复杂; 不确定是否有更短的解决方案.首先,我们计算累积和,对其进行操作,然后返回(diff有点类似于反函数cumsum).

import math

c = values.cumsum() - ALLOWANCE
# now we've got [-15, -5, 20, 50]
c[c < 0] = 0 # negative values don't make sense here

# (c - c.shift(1)) # <-- what I had first: diff by accident

# it is important that we don't fill with 0, in case that the first
# value is greater than ALLOWANCE
c.diff().fillna(math.max(0, values[0] - ALLOWANCE))
Run Code Online (Sandbox Code Playgroud)


EdC*_*ica 5

这可能不是那么高效,但目前这是熊猫用这样做的方式rolling_apply:

In [53]:

ALLOWANCE = 100
def reduce(x):
    global ALLOWANCE
    # short circuit if we've already reached 0
    if ALLOWANCE == 0:
        return x
    val = max(0, x - ALLOWANCE)
    ALLOWANCE = max(0, ALLOWANCE - x)
    return val

pd.rolling_apply(values, window=1, func=reduce)
Out[53]:
0     0
1     0
2    20
3    30
dtype: float64
Run Code Online (Sandbox Code Playgroud)

或者更简单:

In [58]:

values.apply(reduce)
Out[58]:
0     0
1     0
2    20
3    30
dtype: int64
Run Code Online (Sandbox Code Playgroud)