Как применить функцию скользящей агрегации к подмножеству скользящих данных? - PullRequest
1 голос
/ 27 апреля 2019

Предположим, у меня большой набор данных, и я хочу применить операцию прокрутки в течение длительного периода, но хочу применить агрегирование только для небольшого числа точек данных. Могу ли я сделать это с pandas?

Когда я пытаюсь применить срез для результата функции агрегирования, мне кажется, что я опоздал, и все вычисления уже произошли:

small = 10
big = 1000
bigger = 10000000
s = pd.Series(np.arange(bigger))

%time x = s.rolling(big).mean()
%time x = s.rolling(big).mean()[:-small]

Вывод этого:

CPU times: user 306 ms, sys: 162 ms, total: 467 ms
Wall time: 468 ms
CPU times: user 291 ms, sys: 127 ms, total: 418 ms
Wall time: 418 ms

В приведенном выше примере я надеялся, что второе временное выражение будет выполняться быстрее, поскольку мне нужно было только вычислить агрегацию по последним 10 точкам данных, но это заняло столько же времени, сколько и для его вычисления для 10 миллионов. .

Что я здесь не так делаю?

В моем реальном сценарии я использую rolling и expanding, поэтому я ищу решение, которое применимо к обоим. Кроме того, в моем примере big почти совпадает с bigger.

РЕДАКТИРОВАТЬ: Следующее иллюстрирует разницу в производительности расчета скользящего среднего по сравнению с расчетом без избыточных вычислений. Он рассчитывает наивный случай, решение по 3UqU57GnaX, а также «ручной» расчет. Обратите внимание, что ручной расчет - это то, чего я надеюсь достичь в общем случае (очевидно, я не хочу вручную реализовывать каждую функцию агрегирования):

import pandas as pd
import numpy as np

small = 10
big = 10000000
bigger = 100000000
s = pd.Series(np.arange(bigger))

def adjusted_mean(current_mean, removed_element, new_element, length):
    return current_mean + (new_element - removed_element) / length

def rolling_mean_optimisation(small, big):
    current_mean = s[-big-small:-small].mean()

    return [adjusted_mean(current_mean, s.values[-big-x], s.values[-x], big) for x in range(small, 0, -1)]

%time naive = s.rolling(big).mean()[-small:]
%time answer_by_3UqU57GnaX = s[-big-small:].rolling(big).mean()[-small:]
%time manual_mean_optimisation = rolling_mean_optimisation(small, big)

Хотя ответ 3UqU57GnaX является большим улучшением по сравнению с наивным случаем, ручная реализация все еще почти на порядок быстрее (фактическая сумма зависит от размера big против bigger:

CPU times: user 3.31 s, sys: 1.56 s, total: 4.87 s
Wall time: 4.88 s
CPU times: user 292 ms, sys: 154 ms, total: 446 ms
Wall time: 445 ms
CPU times: user 60.3 ms, sys: 21.2 ms, total: 81.4 ms
Wall time: 81.2 ms

1 Ответ

1 голос
/ 27 апреля 2019

Это займет столько же времени, сколько вы впервые применили rolling и mean ко всей серии.

Если вы примените его только к последним 10 точкам данных (s[-10:]), тогда оно будетбыстрее:

s[-10:].rolling(1000).mean()

Это даст вам значения NaN, поскольку вы используете только последние 10 точек данных, но вам нужно 1000 точек данных для скользящего среднего.

Редактировать: Это не даст вамNaNs и должно быть быстрее:

s[-big-small:].rolling(big).mean()[-small:]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...