Вы можете выполнять вычисления в NumPy вместо Pandas.Для ваших входных размеров это будет порядка ~ 5%, не очень интересно, но лучше, чем ничего.Для меньших входов усиление намного более значимо.
import pandas as pd
import numpy as np
arr = np.random.randn(100000, 1000)
df = pd.DataFrame(arr)
x = ((1 + df).cumprod(axis=0) - 1)
y = np.cumprod(1 + arr, axis=0) - 1
print(np.allclose(x, y))
Учитывая, что это тот же результат, время:
arr = np.random.randn(100000, 1000)
df = pd.DataFrame(arr)
%timeit ((1 + df).cumprod(axis=0) - 1)
# 3.64 s ± 76.5 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit np.cumprod(1 + arr, axis=0) - 1
# 3.42 s ± 19 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
показывает вышеупомянутый прирост скорости для ваших входов.
Для меньших входов разница больше, например:
arr = np.random.randn(1000, 10)
df = pd.DataFrame(arr)
%timeit ((1 + df).cumprod(axis=0) - 1)
# 469 µs ± 4.13 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%timeit np.cumprod(1 + arr, axis=0) - 1
# 36.6 µs ± 427 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
, показывающая, что в этом случае вычисления в NumPy в ~ 13 раз быстрее, чем в Pandas.
РЕДАКТИРОВАТЬ:
Как предполагает @hpaulj, np.multiply.accumulate()
может получить немного быстрее.
# for shape = (100000, 1000)
%timeit np.multiply.accumulate(1 + arr, axis=0) - 1
# 3.38 s ± 79.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
и, для небольших входных данных:
# for shape = (1000, 10)
%timeit np.multiply.accumulate(1 + arr, axis=0) - 1
# 35.8 µs ± 423 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
НоКак всегда, такого рода микро-эталоны следует брать с крошкой соли, особенно когда наблюдаются такие небольшие различия.