根据递减值计算新值

时间:2015-02-23 15:13:16

标签: python pandas

问题:

我想做的是逐步减少Series中不断减少的基数值。

我不确定这个术语 - 我确实认为我可以用cumsumdiff做一些事情,但我想我会在那里进行疯狂的追逐......

开始代码:

import pandas as pd

ALLOWANCE = 100
values = pd.Series([85, 10, 25, 30])

期望的输出:

desired = pd.Series([0, 0, 20, 30])

理由:

ALLOWANCE的基础开始 - Series中的每个值都会减少剩余金额,以及配额本身,因此会执行以下步骤:

  • 从100开始,我们可以完全删除85,使其变为0,我们现在15已经ALLOWANCE
  • 下一个值是10,我们仍然可以使用15,因此这又变为0,我们已经5了。
  • 下一个值为25 - 我们只剩下5,因此会变为20,现在我们没有进一步的限额。
  • 下一个值为30,由于没有任何限额,因此值仍为30

4 个答案:

答案 0 :(得分:10)

根据您对cumsumdiff的初步想法,您可以写下:

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

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

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

s = (values.cumsum() - ALLOWANCE).clip_lower(0)
desired = s.diff().fillna(s)

这将使用"第一个值 - 容差"填充第一个NaN值。值。因此,在ALLOWANCE降低到75的情况下,它会将desired作为Series([10, 10, 25, 30])返回。

答案 1 :(得分: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))

答案 2 :(得分: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

或更简单:

In [58]:

values.apply(reduce)
Out[58]:
0     0
1     0
2    20
3    30
dtype: int64

答案 3 :(得分:1)

它应该与while循环一起使用:

ii = 0
while (ALLOWANCE > 0 and ii < len(values)):
    if (ALLOWANCE > values[ii]):
        ALLOWANCE -= values[ii]
        values[ii] = 0
    else:
        values[ii] -= ALLOWANCE
        ALLOWANCE = 0
    ii += 1