rol = DataFrame.rolling(window, min_periods=None, center=False, win_type=None, on=None, axis=no_default, closed=None, step=None, method='single')
Pandas
содержит компактный интерфейс для выполнения оконных операций - операции, которая выполняет агрегацию по скользящему разделу значений. API оконных операций функционирует аналогично APIDataFrame.groupby()
, вызывая метод оконного управления с необходимыми параметрами, а затем впоследствии вызывая функцию агрегирования.
window
- размер скользящего окна. Если передано:
int
- фиксированное количество наблюдений, используемых для каждого окна.timedelta
или offset
- период времени каждого окна. Каждое окно будет иметь переменный размер в зависимости от наблюдений, включенных в период времени. Это справедливо только для индексов типа datetime
. BaseIndexer
- границы окна основаны на методе .get_window_bounds()
. Дополнительные ключевые аргументы, а именно min_ periods
, center
, close
и step
, будут переданы в .get_window_bounds()
.min_periods=None
- минимальное количество наблюдений в окне (принимает int
или None
), необходимое для получения значения. В противном случае результатом будет np.nan
.
min_ periods
по умолчанию будет равно 1.center=False
- если False
, то установит метки окон как правый край индекса окна. Если True
, то установит метки окон в центре индекса окна.
win_type=None
- если None
, то все баллы имеют одинаковый вес. Если это строка, то она должна быть действительная оконная функция scipy.signal
.
Некоторые типы окон Scipy
требуют передачи дополнительных аргументов в функцию агрегирования. Они должны соответствовать ключевым словам, указанным в сигнатуре методов оконных операций Scipy
.
on=None
- для DataFrame
- метка столбца или уровень индекса, на котором рассчитывается скользящее окно, а не индекс DataFrame
. Принимает строку - как метку индекса столбца. Если указать столбец как целочисленный индекс, то он игнорируется и исключается из результата, т.к. целочисленный индекс не используется для вычисления скользящего окна.
axis=no_default
- ключевой аргумент axis
устарел с версии 2.1.0. Теперь для использования axis=1
необходимо транспонировать DataFrame.T
.
index
, обрабатывает строки.columns
, обрабатывает столбцы.Для Series
аргумент не используется и по умолчанию равен 0.
closed=None
- по умолчанию None
(«право»).
right
, первая точка в окне исключается из расчетов.left
, последняя точка в окне исключается из расчетов.both
, ни одна точка в окне не будет исключена из вычислений.neither
, первая и последняя точки в окне исключаются из вычислений.step=None
- оценивает окно при каждом результате шага step
, что эквивалентно срезу как [::step]
. Шаг должен быть целым числом. Использование step
, отличного от None
или 1, приведет к получению результата, форма которого отличается от формы входных данных.
method='single'
- выполняет операцию скользящего окна для одного столбца или строки (single
) или для всего объекта (table
). Этот аргумент реализуется только при указании engine='numba'
в вызове метода.
typing.Window
. В противном случае возвращается экземпляр typing.Rolling
.DataFrame.rolling()
:Метод DataFrame.rolling()
предоставляет расчеты скользящего окна.
Стандартные скользящие окна поддерживают указание окон как фиксированного числа наблюдений или переменного числа наблюдений на основе смещения offset
. Если указано смещение по времени, то соответствующий индекс по времени должен быть монотонным.
>>> import pandas as pd >>> times = ['2020-01-01', '2020-01-03', '2020-01-04', '2020-01-05', '2020-01-29'] >>> s = pd.Series(range(5), index=pd.DatetimeIndex(times)) >>> s # 2020-01-01 0 # 2020-01-03 1 # 2020-01-04 2 # 2020-01-05 3 # 2020-01-29 4 # dtype: int64 # Окно с 2 наблюдениями >>> s.rolling(window=2).sum() # 2020-01-01 NaN # 2020-01-03 1.0 # 2020-01-04 3.0 # 2020-01-05 5.0 # 2020-01-29 7.0 # dtype: float64 # Окно наблюдений на 2 дня вперед >>> s.rolling(window='2D').sum() # 2020-01-01 0.0 # 2020-01-03 1.0 # 2020-01-04 3.0 # 2020-01-05 5.0 # 2020-01-29 4.0 # dtype: float64
Функция | Что делает |
Rolling.count([numeric_only]) | Вычисляет количество переходящих наблюдений, отличных от NaN |
Rolling.sum([numeric_only, engine, ...]) | Рассчитывает скользящую сумму. |
Rolling.mean([numeric_only, engine, ...]) | Рассчитывает скользящее среднее значение |
Rolling.median([numeric_only, engine, ...]) | Рассчитывает скользящую медиану. |
Rolling.var([ddof, numeric_only, engine, ...]) | Рассчитывает скользящую дисперсию |
Rolling.std([ddof, numeric_only, engine, ...]) | Рассчитывает скользящее стандартное отклонение. |
Rolling.min([numeric_only, engine, ...]) | Рассчитывает скользящий минимум |
Rolling.max([numeric_only, engine, ...]) | Рассчитывает скользящий максимум |
Rolling.corr([other, pairwise, ddof, ...]) | Рассчитывает скользящую корреляцию |
Rolling.cov([other, pairwise, ddof, ...]) | Рассчитывает ковариацию скользящей выборки |
Rolling.skew([numeric_only]) | Рассчитывает несмещенную асимметрию. |
Rolling.kurt([numeric_only]) | Рассчитывает определение эксцесса по методу Роллинга Фишера без предвзятости. |
Rolling.apply(func[, raw, engine, ...]) | Применяет пользовательскую функцию агрегирования |
Rolling.aggregate(func, *args, **kwargs) | Агрегирует, используя одну или несколько операций над указанной осью. |
Rolling.quantile(q[, interpolation, ...]) | Рассчитывает квантиль скользящего окна |
Rolling.sem([ddof, numeric_only]) | Рассчитывает стандартную ошибку среднего значения скользящего окна |
Rolling.rank([method, ascending, pct, ...]) | Рассчитывает ранг скользящего окна |
По умолчанию метки устанавливаются у правого края окна, но доступен ключевой аргумент center
, поэтому метки можно установить по центру.
>>> import pandas as pd >>> s = pd.Series(range(10)) >>> s.rolling(window=5).mean() # 0 NaN # 1 NaN # 2 NaN # 3 NaN # 4 2.0 # 5 3.0 # 6 4.0 # 7 5.0 # 8 6.0 # 9 7.0 # dtype: float64 >>> s.rolling(window=5, center=True).mean() # 0 NaN # 1 NaN # 2 2.0 # 3 3.0 # 4 4.0 # 5 5.0 # 6 6.0 # 7 7.0 # 8 NaN # 9 NaN # dtype: float64
Такое поведение также может быть применено к индексам, подобным datetime
.
df = pd.DataFrame( {"A": [0, 1, 2, 3, 4]}, index=pd.date_range("2024", periods=5, freq="1D") ) >>> df # A # 2024-01-01 0 # 2024-01-02 1 # 2024-01-03 2 # 2024-01-04 3 # 2024-01-05 4 >>> df.rolling("2D", center=False).mean() # A # 2024-01-01 0.0 # 2024-01-02 0.5 # 2024-01-03 1.5 # 2024-01-04 2.5 # 2024-01-05 3.5 >>> df.rolling("2D", center=True).mean() # A # 2024-01-01 0.5 # 2024-01-02 1.5 # 2024-01-03 2.5 # 2024-01-04 3.5 # 2024-01-05 4.0
Включение конечных точек интервала в вычисления скользящего окна может быть задано с помощью аргумента closed
:
right
, первая точка в окне исключается из расчетов.left
, последняя точка в окне исключается из расчетов.both
, ни одна точка в окне не будет исключена из вычислений.neither
, первая и последняя точки в окне исключаются из вычислений.Например, наличие открытой нужной конечной точки полезно во многих задачах, которые требуют, чтобы текущая информация не переходила обратно в прошлую информацию. Это позволяет скользящему окну вычислять статистику "до этого момента времени", но не включая этот момент времени.
df = pd.DataFrame( {"x": 1}, index=[ pd.Timestamp("20240101 09:00:01"), pd.Timestamp("20240101 09:00:02"), pd.Timestamp("20240101 09:00:03"), pd.Timestamp("20240101 09:00:04"), pd.Timestamp("20240101 09:00:06"), ], ) >>> df["right"] = df.rolling("2s", closed="right").x.sum() # по умолчанию >>> df["both"] = df.rolling("2s", closed="both").x.sum() >>> df["left"] = df.rolling("2s", closed="left").x.sum() >>> df["neither"] = df.rolling("2s", closed="neither").x.sum() >>> df # x right both left neither # 2024-01-01 09:00:01 1 1.0 1.0 NaN NaN # 2024-01-01 09:00:02 1 2.0 2.0 1.0 1.0 # 2024-01-01 09:00:03 1 2.0 3.0 2.0 1.0 # 2024-01-01 09:00:04 1 2.0 3.0 2.0 1.0 # 2024-01-01 09:00:06 1 1.0 2.0 1.0 NaN
Помимо того, что аргумент window
принимает целое число int
или смещение offset
, также может принимать подкласс BaseIndexer
, который позволяет пользователю определить собственный метод для расчета границ окна. Подкласс BaseIndexer
должен будет определить метод .get_window_bounds
, который возвращает кортеж из двух массивов, первый из которых - начальные индексы окон, а второй - конечные индексы окон. Кроме того, num_values
, min_ periods
, center
, close
и step
будут автоматически передаваться в get_window_bounds
, и определенный пользователем метод должен всегда принимать эти аргументы.
Например, если есть следующий DataFrame
:
>>> use_expanding = [True, False, True, False, True] >>> df = pd.DataFrame({"values": range(5)}) >>> df # values # 0 0 # 1 1 # 2 2 # 3 3 # 4 4
и нужно использовать расширяющееся окно, где use_expanding
имеет значение True
, в противном случае окно размером 1, то можно создать следующий подкласс BaseIndexer
:
>>> from pandas.api.indexers import BaseIndexer >>> import numpy as np class CustomIndexer(BaseIndexer): def get_window_bounds(self, num_values, min_periods, center, closed, step): start = np.empty(num_values, dtype=np.int64) end = np.empty(num_values, dtype=np.int64) for i in range(num_values): if self.use_expanding[i]: start[i] = 0 end[i] = i + 1 else: start[i] = i end[i] = i + self.window_size return start, end >>> indexer = CustomIndexer(window_size=1, use_expanding=use_expanding) >>> df.rolling(indexer).sum() # values # 0 0.0 # 1 1.0 # 2 3.0 # 3 3.0 # 4 10.0
В примерах ниже можно отметить один подкласс VariableOffsetWindowIndexer
, который позволяет выполнять операции скользящего окна по нефиксированному смещению, например BusinessDay
.
>>> from pandas.api.indexers import VariableOffsetWindowIndexer >>> df = pd.DataFrame(range(10), index=pd.date_range("2024", periods=10)) >>> offset = pd.offsets.BDay(1) >>> indexer = VariableOffsetWindowIndexer(index=df.index, offset=offset) >>> df # 0 # 2024-01-01 0 # 2024-01-02 1 # 2024-01-03 2 # 2024-01-04 3 # 2024-01-05 4 # 2024-01-06 5 # 2024-01-07 6 # 2024-01-08 7 # 2024-01-09 8 # 2024-01-10 9 >>> df.rolling(indexer).sum() # 0 # 2024-01-01 0.0 # 2024-01-02 1.0 # 2024-01-03 2.0 # 2024-01-04 3.0 # 2024-01-05 4.0 # 2024-01-06 5.0 # 2024-01-07 11.0 # 2024-01-08 18.0 # 2024-01-09 8.0 # 2024-01-10 9.0
Для некоторых задач знание будущего доступно для анализа. Например, это происходит, когда каждая точка данных представляет собой полный временной ряд, считанный из эксперимента, и задача состоит в том, чтобы извлечь основные условия. В этих случаях может быть полезно выполнить прогнозные вычисления скользящего окна. Для этой цели доступен класс FixedForwardWindowIndexer
. Этот подкласс BaseIndexer
реализует закрытое скользящее окно фиксированной ширины. Его можно использовать его следующим образом:
>>> from pandas.api.indexers import FixedForwardWindowIndexer >>> indexer = FixedForwardWindowIndexer(window_size=2) >>> df.rolling(indexer, min_periods=1).sum() # 0 # 2024-01-01 1.0 # 2024-01-02 3.0 # 2024-01-03 5.0 # 2024-01-04 7.0 # 2024-01-05 9.0 # 2024-01-06 11.0 # 2024-01-07 13.0 # 2024-01-08 15.0 # 2024-01-09 17.0 # 2024-01-10 9.0
Добиться такого поведения также можно используя срез и применяя агрегацию скользящего окна, а затем переворачивая результат, как показано в примере ниже:
df = pd.DataFrame( data=[ [pd.Timestamp("2024-01-01 00:00:00"), 100], [pd.Timestamp("2024-01-01 00:00:01"), 101], [pd.Timestamp("2024-01-01 00:00:03"), 103], [pd.Timestamp("2024-01-01 00:00:04"), 111], ], columns=["time", "value"], ).set_index("time") >>> df # value # time # 2018-01-01 00:00:00 100 # 2018-01-01 00:00:01 101 # 2018-01-01 00:00:03 103 # 2018-01-01 00:00:04 111 >>> reversed_df = df[::-1].rolling("2s").sum()[::-1] >>> reversed_df # value # time # 2018-01-01 00:00:00 201.0 # 2018-01-01 00:00:01 101.0 # 2018-01-01 00:00:03 214.0 # 2018-01-01 00:00:04 111.0
.apply()
для скользящего окна.Метод apply() принимает дополнительный аргумент func
и выполняет общие вычисления скользящего окна. Аргумент func
должен представлять собой одну функцию, которая создает одно значение из входных данных ndarray
. Аргумент raw
указывает, преобразуются ли окна в объекты Series(raw=False)
или в объекты ndarray(raw=True)
.
def mad(x): return np.fabs(x - x.mean()).mean() >>> s = pd.Series(range(10)) >>> s.rolling(window=4).apply(mad, raw=True) # 0 NaN # 1 NaN # 2 NaN # 3 1.0 # 4 1.0 # 5 1.0 # 6 1.0 # 7 1.0 # 8 1.0 # 9 1.0 # dtype: float64
Кроме того, метод .apply()
может использовать Numba, если он установлен как необязательная зависимость. Агрегацию apply
можно выполнить с помощью Numba, указав аргументы engine='numba'
и engine_kwargs
(для аргумента raw
также должно быть установлено значение True
).
Numba будет применяться потенциально в двух случаях:
func
является стандартной функцией Python, движок выполнит JIT переданную функцию. func
также может быть JIT-функцией.for
, в котором метод .apply()
применяется к каждому окну.Аргумент engine_kwargs
- это словарь ключевых аргументов, которые будут переданы в декоратор numba.jit
. Эти аргументы будут применяться как к переданной функции (если это стандартная функция Python), так и к циклу apply for
для каждого окна.
Методы cov() и corr() могут вычислять статистику перемещения окна по двум Series
или любой комбинации DataFrame
/Series
или DataFrame
/DataFrame
. Рассмотрим поведение в каждом случае:
Series
: вычисляет статистику для пары.DataFrame
/Series
: вычисляет статистику для каждого столбца DataFrame
с переданной серией, возвращая таким образом DataFrame
.DataFrame
/DataFrame
: по умолчанию вычисляет статистику соответствия имен столбцов, возвращая DataFrame
. Если передан аргумент pairwise=True
, то вычисляет статистику для каждой пары столбцов, возвращая DataFrame
с MultiIndex
, значениями которого являются рассматриваемые даты.Например:
df = pd.DataFrame( np.random.randn(10, 4), index=pd.date_range("2020-01-01", periods=10), columns=["A", "B", "C", "D"], ) >>> df = df.cumsum() >>> df2 = df[:4] >>> df2.rolling(window=2).corr(df2["B"]) # A B C D # 2020-01-01 NaN NaN NaN NaN # 2020-01-02 -1.0 1.0 1.0 1.0 # 2020-01-03 1.0 1.0 -1.0 1.0 # 2020-01-04 1.0 1.0 -1.0 1.0
В анализе финансовых данных и других областях обычно вычисляют ковариационные и корреляционные матрицы для набора временных рядов. Часто также интересуют ковариационные и корреляционные матрицы в скользящем окне. Это можно сделать, передав аргумент pairwise
, который в случае входных данных DataFrame
выдаст MultiIndex
, индексом которого являются рассматриваемые даты. В случае одного аргумента DataFrame
аргумент pairwise
может быть даже опущен:
Примечание. Пропущенные значения игнорируются, и каждая запись вычисляется с использованием попарных полных наблюдений.
Предполагая, что недостающие данные отсутствуют случайным образом, это приводит к оценке ковариационной матрицы, которая является несмещенной. Однако для многих приложений эта оценка может оказаться неприемлемой, т.к. не гарантируется, что оцененная ковариационная матрица будет положительно полуопределенной. Это может привести к тому, что оценочные корреляции будут иметь абсолютные значения, превышающие единицу, и/или необратимую ковариационную матрицу.
covs = ( df[["B", "C", "D"]] .rolling(window=4) .cov(df[["A", "B", "C"]], pairwise=True) ) >>> covs # B C D # 2020-01-01 A NaN NaN NaN # B NaN NaN NaN # C NaN NaN NaN # 2020-01-02 A NaN NaN NaN # B NaN NaN NaN # C NaN NaN NaN # 2020-01-03 A NaN NaN NaN # B NaN NaN NaN # C NaN NaN NaN # 2020-01-04 A 0.570713 -0.029821 0.382259 # B 2.987649 0.168730 1.743468 # C 0.168730 0.394460 0.140073 # 2020-01-05 A 0.401121 -0.105891 0.298607 # B 1.534023 -0.455098 0.932260 # C -0.455098 0.141586 -0.257665 # 2020-01-06 A 0.328475 -0.095758 -0.375328 # B 0.590550 -0.181626 -0.778261 # C -0.181626 0.063990 0.321139 # 2020-01-07 A 0.090902 -0.168251 -0.280190 # B 1.472003 0.082712 -1.158504 # C 0.082712 0.121967 0.081700 # 2020-01-08 A -0.211723 -0.278281 -0.096997 # B 1.085040 0.875290 -0.736516 # C 0.875290 1.261084 -0.226900 # 2020-01-09 A -0.243264 0.321226 0.203174 # B 0.326425 0.544196 0.084798 # C 0.544196 1.523514 0.308076 # 2020-01-10 A -0.181656 0.360408 0.278193 # B 0.068862 0.034841 -0.032263 # C 0.034841 0.767510 -0.066379
Аргумент win_type
в .rolling()
генерирует взвешенные окна, которые обычно используются при фильтрации и спектральной оценке. Аргумент win_type
должен быть строкой, соответствующей оконной функции scipy.signal
. Для использования этих окон должен быть установлен Scipy
, а дополнительные аргументы, которые принимают оконные методы Scipy
, должны быть указаны в функции агрегации.
>>> s = pd.Series(range(10)) >>> s.rolling(window=5).mean() # 0 NaN # 1 NaN # 2 NaN # 3 NaN # 4 2.0 # 5 3.0 # 6 4.0 # 7 5.0 # 8 6.0 # 9 7.0 # dtype: float64 >>> s.rolling(window=5, win_type="triang").mean() # 0 NaN # 1 NaN # 2 NaN # 3 NaN # 4 2.0 # 5 3.0 # 6 4.0 # 7 5.0 # 8 6.0 # 9 7.0 # dtype: float64 # Дополнительные аргументы `Scipy`, передаваемые в функцию агрегации >>> s.rolling(window=5, win_type="gaussian").mean(std=0.1) # 0 NaN # 1 NaN # 2 NaN # 3 NaN # 4 2.0 # 5 3.0 # 6 4.0 # 7 5.0 # 8 6.0 # 9 7.0 # dtype: float64
Функция | Что делает |
Window.mean([numeric_only]) | Вычисляет среднее значение скользящего взвешенного окна |
Window.sum([numeric_only]) | Вычисляет сумму скользящего взвешенного окна |
Window.var([ddof, numeric_only]) | Вычисляет дисперсию скользящего взвешенного окна |
Window.std([ddof, numeric_only]) | Вычисляет стандартное отклонение скользящего взвешенного окна |
DataFrame.rolling()
>>> import pandas as pd >>> import numpy as np >>> df = pd.DataFrame({'B': [0, 1, 2, np.nan, 4]}) >>> df # B # 0 0.0 # 1 1.0 # 2 2.0 # 3 NaN # 4 4.0
window
Скользящая сумма с длиной окна в 2 наблюдения.
>>> df.rolling(2).sum() # B # 0 NaN # 1 1.0 # 2 3.0 # 3 NaN # 4 NaN
Скользящая сумма с интервалом в 2 секунды.
df_time = pd.DataFrame({'B': [0, 1, 2, np.nan, 4]}, index=[pd.Timestamp('20240101 09:00:00'), pd.Timestamp('20240101 09:00:02'), pd.Timestamp('20240101 09:00:03'), pd.Timestamp('20240101 09:00:05'), pd.Timestamp('20240101 09:00:06')]) >>> df_time # B # 2024-01-01 09:00:00 0.0 # 2024-01-01 09:00:02 1.0 # 2024-01-01 09:00:03 2.0 # 2024-01-01 09:00:05 NaN # 2024-01-01 09:00:06 4.0 >>> df_time.rolling('2s').sum() # B # 2024-01-01 09:00:00 0.0 # 2024-01-01 09:00:02 1.0 # 2024-01-01 09:00:03 3.0 # 2024-01-01 09:00:05 NaN # 2024-01-01 09:00:06 4.0
Скользящая сумма с окнами, ориентированными вперед, с 2 наблюдениями.
>>> indexer = pd.api.indexers.FixedForwardWindowIndexer(window_size=2) >>> df.rolling(window=indexer, min_periods=1).sum() # B # 0 1.0 # 1 3.0 # 2 2.0 # 3 4.0 # 4 4.0
min_periods
Скользящая сумма с длиной окна в 2 наблюдения, но для вычисления значения требуется минимум 1 наблюдение.
>>> df.rolling(2, min_periods=1).sum() # B # 0 0.0 # 1 1.0 # 2 3.0 # 3 2.0 # 4 4.0
center
Скользящая сумма с результатом, присвоенным центру индекса окна.
>>> df.rolling(3, min_periods=1, center=True).sum() # B # 0 1.0 # 1 3.0 # 2 3.0 # 3 6.0 # 4 4.0 >>> df.rolling(3, min_periods=1, center=False).sum() # B # 0 0.0 # 1 1.0 # 2 3.0 # 3 3.0 # 4 6.0
step
Скользящая сумма с длиной окна в 2 наблюдения, минимум 1 наблюдение для вычисления значения и шагом в 2.
>>> df.rolling(2, min_periods=1, step=2).sum() # B # 0 0.0 # 2 3.0 # 4 4.0
win_type
Скользящая сумма с длиной окна 2, используя тип окна Scipy
'gaussian'.
>>> df.rolling(2, win_type='gaussian').sum(std=3) # B # 0 NaN # 1 0.986207 # 2 2.958621 # 3 NaN # 4 NaN
on
Скользящая сумма с окном продолжительностью 2 дня
df = pd.DataFrame({ 'A': [pd.to_datetime('2024-01-01'), pd.to_datetime('2024-01-01'), pd.to_datetime('2024-01-02'),], 'B': [1, 2, 3], }, index=pd.date_range('2020', periods=3)) >>> df # A B # 2020-01-01 2024-01-01 1 # 2020-01-02 2024-01-01 2 # 2020-01-03 2024-01-02 3 >>> df.rolling('2D', on='A').sum() # A B # 2020-01-01 2024-01-01 1.0 # 2020-01-02 2024-01-01 3.0 # 2020-01-03 2024-01-02 6.0