Python Pandas DataFrame的指数衰减
我正在尝试高效地计算一个Pandas数据框中每一列的带有指数衰减的滚动总和。这个数据框包含了世界上每个国家的每日得分。数据框的样子是这样的:
AF UK US
2014-07-01 0.998042 0.595720 0.524698
2014-07-02 0.380649 0.838436 0.355149
2014-07-03 0.306240 0.274755 0.964524
2014-07-04 0.396721 0.836027 0.225848
2014-07-05 0.151291 0.677794 0.603548
2014-07-06 0.558846 0.050535 0.551785
2014-07-07 0.463514 0.552748 0.265537
2014-07-08 0.240282 0.278825 0.116432
2014-07-09 0.309446 0.096573 0.246021
2014-07-10 0.800977 0.583496 0.713893
我不太确定如何在不逐行遍历数据框的情况下计算这个滚动总和(带衰减),因为我需要知道昨天的得分才能计算今天的得分。而要计算昨天的得分,我又需要知道前天的得分,依此类推。这是我一直在使用的代码,但我希望能找到一种更高效的方法来实现这个目标。
for j, val in df.iteritems():
for i, row in enumerate(val):
df[j].iloc[i] = row + val[i-1]*np.exp(-0.05)
1 个回答
9
你可以利用一个事实:当指数相乘时,它们的指数会相加。
比如:
N(2) = N(2) + N(1) * exp(-0.05)
N(3) = N(3) + (N(2) + N(1) * exp(-0.05))*exp(-0.05)
N(3) = N(3) + N(2)*exp(-0.05) + N(1)*exp(-0.1)
N(4) = ...and so on
接下来可以用numpy来进行向量化处理:
dataset = pd.DataFrame(np.random.rand(1000,3), columns=["A", "B","C"])
weightspace = np.exp(np.linspace(len(dataset), 0, num=len(dataset))*-0.05)
def rollingsum(array):
weights = weightspace[0-len(array):]
# Convolve the array and the weights to obtain the result
a = np.dot(array, weights).sum()
return a
a = pd.expanding_apply(dataset, rollingsum)
pd.expanding_apply
这个函数会把滚动求和的操作反向应用到每一行上,调用它的次数是len(dataset)
。np.linspace
会生成一个大小为len(dataset)
的数据集,并计算当前行每次乘以exp(-0.05)
的次数。
因为这个过程是向量化的,所以应该会很快:
%timeit a = pd.expanding_apply(dataset, rollingsum)
10 loops, best of 3: 25.5 ms per loop
这和下面的比较(注意我使用的是python 3,并且对第一行的行为做了一些修改...):
def multipleApply(df):
for j, val in df.iteritems():
for i, row in enumerate(val):
if i == 0:
continue
df[j].iloc[i] = row + val[i-1]*np.exp(-0.05)
最后的结果是:
In[68]: %timeit multipleApply(dataset)
1 loops, best of 3: 414 ms per loop