加速使用前几行结果的行操作

Speeding up a row operation that uses the result of previous rows

我有一些来自加速度计的数据,我试图在其中平滑这些值。我遇到的问题是我的数据框包含大约。 1,000,000 行和 运行 smoothing 函数因此需要几分钟(我在 jupyter 中 运行)

def smoothing(df, alpha, length):
    df['x'][0] = df['x'][0] * alpha

    for i in range(1,length):
        df['x'][i] = df['x'][i-1]+alpha*(df['x'][i] - df['x'][i-1])

    return df

我的问题是,是否可以通过使用矢量化、pandas.apply 或类似方法来增强或加速此计算。请注意,我自己尝试过使用这些方法,但没有任何运气,因为我未能产生正确的结果。我正在努力解决的部分是获取前几行的结果,但我不确定如何获取,例如使用 .shift() 获得与 smoothing 函数

相同的功能

这是一些示例数据:

x_list = [21,42,49,8,0,-57,-137, -135,-177, -181]
data = pd.DataFrame(x_list, columns=['x'])
smoothing(data, 0.02, len(x_list))

预期结果:

    x
0   0
1   0
2   0
3   0
4   0
5  -1
6  -3
7  -5
8  -8
9 -11

您可以在全局变量的帮助下使用 apply 来存储计算值以获得所需的输出

store = 0
def m(x):
    global store 
    if x == data['x'][0]:
        store = 0.2*x
        return store
    else :     
        store = (store+alpha*(x - store))
        return store    

data['x'].apply(m)

输出:

0     4.200000
1    11.760000
2    19.208000
3    16.966400
4    13.573120
5    -0.541504
6   -27.833203
7   -49.266563
8   -74.813250
9   -96.050600
Name: x, dtype: float64
%%timeit
data['x'].apply(m)
1000 loops, best of 3: 478 µs per loop

n = pd.concat([data['x']]*10000).reset_index(drop=True) # in function condtion shld be n[0] instead of data['x'][0]
n.apply(m)
1 loop, best of 3: 2.18 s per loop

这是 numba 方法,它比 OP 中的函数快很多(10,000 行大约快 20,000 倍,这不是错字!):

from numba import njit

@njit
def smoothing_numba(x,alpha):
    x[0] = x[0] * alpha

    for i in range(1,len(x)):
        x[i] = x[i-1] + alpha * ( x[i] - x[i-1] )

    return x

smoothing_numba(data.x.values,0.02)

如果你在上面的代码中没有使用 @njit 装饰器,你将拥有一个标准的 numpy 函数。这比 numba 慢了大约 150 倍,但仍然比原始函数快 150 倍。

这是 10,000 行时的时间。

np.random.seed(123)
data = pd.DataFrame(np.random.randn(10000), columns=['x'])

%timeit smoothing(data, 0.02, len(data))
1 loop, best of 3: 995 ms per loop

%timeit smoothing_numba(data.x.values, 0.02)
10000 loops, best of 3: 41.8 µs per loop

在这种循环不可避免的情况下,将 pandas 函数转换为 numpy/numba 函数会显着加快速度,这当然并不罕见。另请注意,numba 旨在与 numpy 配合使用,因此一旦将函数从 pandas 转换为 numpy,通常可以使用 @njit 装饰以提高速度。