Когда я первоначально пытался ускорить это, я использовал ваши данные, но 5 строк было недостаточно для подтверждения фактических данных.Поэтому я создал гораздо больший кадр данных (1 тыс. Строк) с 2 символами, используя тот же формат, который у вас уже есть.Вот код для копирования моих тестовых данных:
import pandas as pd # version 0.23.4
import numpy as np # version 1.15.4
np.random.seed(1)
df1 = pd.DataFrame(index=[
pd.date_range(start='1962-01-02', periods=1000, freq='D'),
['AA']*500 + ['BB']*500
], columns=[
'price_open',
'price_high',
'price_low',
'price_close',
'volume',
'price_adj_close'
], data=np.random.random(size=(1000, 6)))
df1.index.names = ['date', 'symbol']
Я рассчитал ваш исходный код, используя эти новые данные:
%%timeit
features_targets_df = pd.DataFrame()
for s in df1.index.unique(level='symbol'):
stock_df = df1.iloc[df.index.get_level_values('symbol') == s].copy()
for c in stock_df:
for n in [1, 3, 5, 10, 15, 30]: # make day-change columns
stock_df['{}_{}d_pct'.format(c, str(n))] = stock_df[c].pct_change(n)
stock_df = stock_df.replace([np.inf, -np.inf], np.nan)
stock_df['price_7d_future'] = stock_df['price_adj_close'].shift(-2).pct_change(2)
features_targets_df = features_targets_df.append(stock_df)
Вывод
159 ms ± 23.6 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
Мой кодзаменяет некоторые из for-loops
на groupby()
и apply()
:
%%timeit
# copy original df instead of defining empty one
features_targets_df = df1.copy()
# loop through the day changes
for n in [1, 3, 5, 10, 15, 30]:
# groupby the "symbol" index level
# focus on the necessary columns (otherwise the second + loops will calculate pct_change across all new columns)
# apply pct_change to each series using lambda
# add suffix to the new columns (I used f-strings because I'm using Python 3.7.1, but these became available in 3.6)
# replace +/- infinity with nan
# join to features_targets_df
features_targets_df = features_targets_df.join(features_targets_df.groupby(level='symbol')[
[
'price_open',
'price_high',
'price_low',
'price_close',
'volume',
'price_adj_close'
]
].apply(lambda x : x.pct_change(n)).add_suffix(f"_{n}d_pct")).replace([np.inf, -np.inf], np.nan)
# groupby "symbol" index level and calculate 7d future
features_targets_df['price_7d_future'] = features_targets_df.groupby(level='symbol').price_adj_close.shift(-2).pct_change(2)
Output
88.4 ms ± 22.2 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
Сокращает время почти на 50%.Надеюсь, это поможет некоторым!