Ускоренный способ забрать сумму вперед после группового? - PullRequest
0 голосов
/ 03 июля 2019

Я пытаюсь получить прямую n-минутную доходность акций в день, учитывая кадр данных со строками, соответствующими доходам через некоторые интервалы.

Я пытался использовать dask и многопоточность скользящего вычисления для каждой группы, но, похоже, это самый быстрый способ сделать это, что я могу выяснить. Тем не менее, для большого кадра данных (миллионы строк) (252 дня и 1000 акций) этот шаг занимает до 40 минут.

ret_df.sort_values(['date','time','stock'], ascending=False, inplace=True)
gb = ret_df.groupby(['date','stock'])
forward_sum_df = gb.rolling(4, on='time', min_periods = 0)['interval_return'].sum().reset_index()

Это вернет сумму следующих 4 раз (по дате и запасу) для каждой строки в кадре данных, как и ожидалось, но делает это довольно медленно. Спасибо за помощь!

РЕДАКТИРОВАТЬ: добавлен пример для уточнения

          date    stock            time      interval_ret
0   2017-01-03  10000001    09:30:00.000000   0.001418
1   2017-01-03  10000001    09:40:00.000000   0.000000
2   2017-01-03  10000001    09:50:00.000000   0.000000
3   2017-01-03  10000001    10:00:00.000000  -0.000474
4   2017-01-03  10000001    10:10:00.000000  -0.001417
5   2017-01-03  10000001    10:20:00.000000  -0.000944
6   2017-01-03  10000001    10:30:00.000000   0.000000
7   2017-01-03  10000001    10:40:00.000000   0.000000
8   2017-01-03  10000001    10:50:00.000000   0.000000
9   2017-01-03  10000001    11:00:00.000000  -0.000472

и т. Д. На складе 10000002 ... и дата 2017-01-04 ....

Например, если мой период удержания составляет 30 минут вместо 10 минут, я хотел бы суммировать 3 строки 'interval_ret', сгруппированные по дате и запасу. Пример:

        date      stock            time           interval_ret_30
0   2017-01-03  10000001    09:30:00.000000   0.001418
1   2017-01-03  10000001    09:40:00.000000   0.000000 - 0.000474
2   2017-01-03  10000001    09:50:00.000000   0.000000 - 0.000474 - 0.001417
3   2017-01-03  10000001    10:00:00.000000  -0.000474 - 0.001417 - 0.000944
4   2017-01-03  10000001    10:10:00.000000  -0.001417 - 0.000944
5   2017-01-03  10000001    10:20:00.000000  -0.000944
6   2017-01-03  10000001    10:30:00.000000   0.000000
7   2017-01-03  10000001    10:40:00.000000  -0.000472
8   2017-01-03  10000001    10:50:00.000000  -0.000472
9   2017-01-03  10000001    11:00:00.000000  -0.000472

1 Ответ

0 голосов
/ 04 июля 2019

Я не знаю, можете ли вы адаптировать это к пандам, но вы можете получить скользящие кумулятивные суммы для 20 миллионов значений в секунду, используя numpy:

N         = 20000000
stocks    = (np.random.random(N)*100)
window    = 4
cumStocks = np.cumsum(np.append(stocks,np.zeros(window)))
rollSum   = cumStocks[window:] - cumStocks[:-window]

Хитрость заключается в том, чтобы вычислить кумулятивную сумму для всего массива, а затем вычесть результирующий массив из себя со смещением, соответствующим размеру вашего окна.

Исходный массив cumsum дополняется нулями, чтобы сохранить исходный размер. Последние несколько элементов, которые ближе к концу массива, чем размер окна, получат скользящую сумму только оставшихся значений. Если вам не нужны эти «неполные» суммы, вы можете просто использовать cumStocks = np.cumsum(stocks), и вычисление сможет сделать 100 миллионов значений в секунду.

Кто-то, кажется, нашел решение этой проблемы с помощью панд здесь: https://stackoverflow.com/a/56886389/5237560

df.groupby(level=0).cumsum() - df.groupby(level=0).cumsum().shift(5)
...