Pandas 求和与滞后值的条件乘积?
我想要得到一个累积和,这个累积和会根据另一个变量的乘积和之前的累积和的值来变化(听起来有点像数学术语,我知道……请耐心听我说)
下面是一个例子的设置:
import pandas as pd
df = pd.DataFrame([1,1,1.004878,1,1.043394],columns=['xx'])
df['n'] = 1000000.0
这会组合成:
xx n
0 1.000000 1000000
1 1.000000 1000000
2 1.004878 1000000
3 1.000000 1000000
4 1.043394 1000000
现在,我们需要把 xx
乘以前一个的 n
值,然后逐步计算这个值的累积和:
cs = pd.Series([0.0] * len(df))
cs[0] = df.ix[0]['n']
for i,e in enumerate(df.iterrows()):
if i == 0: continue
cs[i] = df.ix[i]['xx'] * cs[(i - 1)]
这样就会产生以下结果:
0 1000000.000000
1 1000000.000000
2 1004878.000000
3 1004878.000000
4 1048483.675932
dtype: float64
问题是:有没有办法在 pandas/numpy 中做到这一点,而不需要逐行处理?如果没有,在被迫逐行处理时,有没有什么优化代码的小技巧?创造性地设计一个索引能否帮助到这个情况?在处理超过10000行的数据时,性能是个问题。
2 个回答
1
我不太明白'n'到底是用来干嘛的(它是不是总是等于1,000,000?),不过用cumprod来匹配你上面的结果还是挺简单的:
In [60]: df.xx.cumprod() * 1e6
Out[60]: 0 1000000.000000
1 1000000.000000
2 1004878.000000
3 1004878.000000
4 1048483.675932
4
首先,你的for循环可以简化成:
for i in xrange(1, len(df)):
cs[i] = df.ix[i]['xx'] * cs[(i - 1)]
(更多数学的复杂内容)每个在 cs[1:]
中的项都是 df['xx']
中所有之前项的乘积(累积乘积),再乘以 df
中 n
列的第一个项。
>>> df
xx n
0 1.000000 1000000
1 1.000000 1000000
2 1.004878 1000000
3 1.000000 1000000
4 1.043394 1000000
>>> a = df['xx']
>>> a
0 1.000000
1 1.000000
2 1.004878
3 1.000000
4 1.043394
Name: xx, dtype: float64
>>> a = a.cumprod()
>>> a
0 1.000000
1 1.000000
2 1.004878
3 1.004878
4 1.048484
Name: xx, dtype: float64
>>> a = a * df['n'][0]
>>> a
0 1000000.000000
1 1000000.000000
2 1004878.000000
3 1004878.000000
4 1048483.675932
Name: xx, dtype: float64
>>> np.all(a == cs)
True
>>>
a = df['xx'].cumprod() * df['n'][0]
这不是一个技巧。之所以能这样做,是因为 df['xx'][0]
的值是1。如果它是其他任何值,并且 cs[0] = df.ix[0]['n']
不是一个简化方式,那么 cumprod
就不管用了。
展开每个 cs
的项会得到:
cs[0] = df['n'][0]
cs[1] = df['xx'][1] * df['n'][0]
cs[2] = df['xx'][2] * df['xx'][1] * df['n'][0]
cs[3] = df['xx'][3] * df['xx'][2] * df['xx'][1] * df['n'][0]
cs[4] = df['xx'][4] * df['xx'][3] * df['xx'][2] * df['xx'][1] * df['n'][0]
因为 df['xx'][0]
等于1,并且 df['xx'][0] * df['n'][0] == df['n'][0]
,所以:
cs[0] = df['xx'][0] * df['n'][0]
cs[1] = df['xx'][1] * df['xx'][0] * df['n'][0]
cs[2] = df['xx'][2] * df['xx'][1] * df['xx'][0] * df['n'][0]
cs[3] = df['xx'][3] * df['xx'][2] * df['xx'][1] * df['xx'][0] * df['n'][0]
cs[4] = df['xx'][4] * df['xx'][3] * df['xx'][2] * df['xx'][1] * df['xx'][0] * df['n'][0]
如果你稍微改变一下问题的条件,比如在每次迭代后需要从上一次计算的n值中减去0.05%,那么cumprod还有效吗?
如果你做了项展开的练习,你应该会发现新的条件导致了乘以一个缩放因子的累积乘积。可以有两种方法来处理这个问题——这两种方法都会在循环计算中产生一些小的浮点误差。再次强调,你需要考虑到 df['xx']
中第一个项的值是1。
for i in xrange(1, len(df)):
cs[i] = df.ix[i]['xx'] * (.9995 * cs[(i - 1)])
>>> k
array([ 1. , 0.9995, 0.9995, 0.9995, 0.9995])
>>> z = df['xx'] * k
>>> z
0 1.000000
1 0.999500
2 1.004376
3 0.999500
4 1.042872
Name: xx, dtype: float64
>>> z = z.cumprod() * df['n'][0]
>>> cs - z
0 0.000000e+00
1 0.000000e+00
2 0.000000e+00
3 0.000000e+00
4 -1.164153e-10
dtype: float64
>>>
>>> z = df['xx'].cumprod() * df['n'][0]
>>> z *= k.cumprod()
>>> cs - z
0 0.000000e+00
1 0.000000e+00
2 -1.164153e-10
3 0.000000e+00
4 0.000000e+00
dtype: float64
>>>