оптимизация кадра данных pandas с подвижным окном

#python #pandas

Вопрос:

У меня есть серия панд, как эта:

 dist
0.02422
0.03267
0.04208
0.05229
0.06291
...
 

В нем почти 200 тысяч строк.
Есть ли более эффективный способ выполнить следующую операцию:

 df["dist"].rolling(3000).apply(lambda x: x.iloc[-1] - x[x != 0].iloc[0] if x[x != 0].shape[0] else 0).dropna().max()
 

На практике мне нужно вычислить разницу между первым ненулевым и последним значением каждого окна. Приведенный выше код работает, но я хотел бы знать, есть ли более эффективный способ выполнить ту же операцию.

Спасибо за вашу помощь.

Ответ №1:

Проблема с вашим кодом заключается в том, что он выполняет слишком много сравнений с 0. Поскольку значение в dist столбце не меняется, сравните его один раз и повторно используйте результат.

Вот как это сделать:

 # The scale of our problem
n = 200_000
window_size = 3_000

# Some simulated data. 20% of `dist` is zero
n_zero = int(n * 0.2)
dist = np.hstack([np.zeros(n_zero), np.random.uniform(0, 1, n - n_zero)])
np.random.shuffle(dist)

df = pd.DataFrame({
    'dist': dist
})

# -----------------

# Convert dist to a numpy array. We do not need pandas series here
dist = df['dist'].to_numpy()

# Find the indexes of all non-zero elements. nz = non-zero
nz_index, = np.nonzero(dist)

# For each row in `dist`, find the first non-zero value within
# the next `window_size` rows. Return NaN if no such value
# can be found.
dist_nz = np.empty_like(dist)
idx = 0
for i in range(len(dist)):
    idx  = 1 if i > nz_index[idx] else 0
    dist_nz[i] = dist[nz_index[idx]] if idx < len(nz_index) and (idx - i < window_size) else np.nan

(dist[window_size-1:] - dist_nz[:-window_size 1]).max()
 

Это завершается за 0,3 секунды по сравнению с 2 м 13 секунд оригинала.

Комментарии:

1. Спасибо за вашу помощь!