问题:
我想做的是逐步减少Series
中不断减少的基数值。
我不确定这个术语 - 我确实认为我可以用cumsum
和diff
做一些事情,但我想我会在那里进行疯狂的追逐......
开始代码:
import pandas as pd
ALLOWANCE = 100
values = pd.Series([85, 10, 25, 30])
期望的输出:
desired = pd.Series([0, 0, 20, 30])
理由:
从ALLOWANCE
的基础开始 - Series
中的每个值都会减少剩余金额,以及配额本身,因此会执行以下步骤:
85
,使其变为0
,我们现在15
已经ALLOWANCE
10
,我们仍然可以使用15
,因此这又变为0
,我们已经5
了。25
- 我们只剩下5
,因此会变为20
,现在我们没有进一步的限额。30
,由于没有任何限额,因此值仍为30
。答案 0 :(得分:10)
根据您对cumsum
和diff
的初步想法,您可以写下:
>>> (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)
cumsum
和diff
的想法有效。它看起来并不复杂;不确定是否有更短的解决方案。首先,我们计算累积和,对其进行操作,然后返回(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