Каков наилучший способ векторизации / оптимизации этого кода Python? - PullRequest
1 голос
/ 27 сентября 2019

Я вычисляю 48 производных панд столбцов, перебирая и вычисляя каждый столбец за раз, но мне нужно ускорить процесс.Каков наилучший способ сделать это, чтобы сделать это быстрее и эффективнее.В каждом столбце рассчитывается цена закрытия в процентах от максимальной и низкой цены периода (T, T-1, T-2 и т. Д.).

Код, который я сейчас использую:

#get last x closes as percentage of period high and low
for i in range(1, 49, 1):
    df.loc[:,'Close_T_period_'+str(i)] = ((df['BidClose'].shift(i).values 
    - df['BidLow'].shift(i).values)/          
    (df['BidHigh'].shift(i).values - df['BidLow'].shift(i).values))

Пример входного кадра данных:

                     BidOpen  BidHigh   BidLow  BidClose  AskOpen  AskHigh   AskLow  AskClose   Volume
Date                                                                                                  
2019-09-27 09:00:00  1.22841  1.22919  1.22768   1.22893  1.22850  1.22927  1.22777   1.22900  12075.0
2019-09-27 10:00:00  1.22893  1.23101  1.22861   1.23058  1.22900  1.23110  1.22870   1.23068  16291.0
2019-09-27 11:00:00  1.23058  1.23109  1.22971   1.23076  1.23068  1.23119  1.22979   1.23087  10979.0
2019-09-27 12:00:00  1.23076  1.23308  1.23052   1.23232  1.23087  1.23314  1.23062   1.23241  16528.0
2019-09-27 13:00:00  1.23232  1.23247  1.23163   1.23217  1.23241  1.23256  1.23172   1.23228  14106.0

Пример выходного кадра данных:

                     BidOpen  BidHigh   BidLow  BidClose  ...  Close_T_period_45  Close_T_period_46  Close_T_period_47  Close_T_period_48
Date                                                      ...                                                                            
2019-09-27 09:00:00  1.22841  1.22919  1.22768   1.22893  ...           0.682635           0.070796           0.128940           0.794521
2019-09-27 10:00:00  1.22893  1.23101  1.22861   1.23058  ...           0.506024           0.682635           0.070796           0.128940
2019-09-27 11:00:00  1.23058  1.23109  1.22971   1.23076  ...           0.774920           0.506024           0.682635           0.070796
2019-09-27 12:00:00  1.23076  1.23308  1.23052   1.23232  ...           0.212500           0.774920           0.506024           0.682635
2019-09-27 13:00:00  1.23232  1.23247  1.23163   1.23217  ...           0.378882           0.212500           0.774920           0.506024

1 Ответ

1 голос
/ 27 сентября 2019

Короткий ответ (более быстрая реализация)

следующий код в 6 раз быстрее:

import numpy as np

def my_shift(x, i):
    first = np.array([np.nan]*i)
    return np.append(first, x[:-i])

result = ((df2['BidClose'].values - df2['BidLow'].values)/(df2['BidHigh'].values - df2['BidLow'].values))
for i in range(1, 49, 1):
    df2.loc[:,'Close_T_period_'+str(i)] = my_shift(result, i)

Длинный ответ (объяснение)

Две основные проблемы узкого места в вашемкод:

  1. На каждой итерации вы пересчитываете одни и те же значения, единственное отличие состоит в том, что каждый раз они сдвигаются по-разному;
  2. Операция сдвига панд очень медленная для вашей цели.

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

Время выполнения

С кадром данных с 5000 строками эталон времени дает:

42 ms ± 1.79 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

, с моим решением я получил:

7.62 ms ± 140 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

ОБНОВЛЕНИЕ

Я пытался реализовать решение с применением:

result = ((df2['BidClose'].values - df2['BidLow'].values)/(df2['BidHigh'].values - df2['BidLow'].values))
df3 = df.reindex(df2.columns.tolist() +[f'Close_T_period_{i}' for i in range(1, 2000)], axis=1)
df3.iloc[:, 9:] = df3.iloc[:, 9:].apply(lambda row: my_shift(result, int(row.name.split('_')[-1])))

В моем тесте это решение выглядит немного медленнее, чем первое.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...