#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. Спасибо за вашу помощь!