Python Pandas DataFrame上的指数衰减

idu*_*s11 6 python numpy pandas

我正在尝试有效地计算Pandas DataFrame的每列的指数衰减的运行总和.DataFrame包含世界上每个国家/地区的每日分数.DataFrame看起来像这样:

                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
Run Code Online (Sandbox Code Playgroud)

我不知道如何在不迭代数据帧的情况下计算滚动总和(衰减),因为我需要知道昨天的分数来计算今天的分数.但是要计算昨天的分数,我需要知道前天的分数等等.这是我一直在使用的代码,但我想要一个更有效的方法来解决它.

for j, val in df.iteritems():
    for i, row in enumerate(val):
        df[j].iloc[i] = row + val[i-1]*np.exp(-0.05)
Run Code Online (Sandbox Code Playgroud)

und*_*ock 8

您可以使用以下事实:当指数乘以其指数时添加:

例如:

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
Run Code Online (Sandbox Code Playgroud)

然后可以使用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)
Run Code Online (Sandbox Code Playgroud)

pd.expanding_apply将rollingsum函数向后应用于每一行,调用它的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
Run Code Online (Sandbox Code Playgroud)

与之相比(注意我使用的是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)
Run Code Online (Sandbox Code Playgroud)

这表现为:

In[68]: %timeit multipleApply(dataset)
1 loops, best of 3: 414 ms per loop
Run Code Online (Sandbox Code Playgroud)