Сообщить об ошибке.

Метод DataFrame.rolling() модуля pandas в Python

Вычисляет скользящее окно в pandas

Синтаксис:

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 оконных операций функционирует аналогично API DataFrame.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.
    • Для окна, заданного целым числом, min_ periods по умолчанию будет соответствовать размеру окна.

  • 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.

    • если 0 или index, обрабатывает строки.
    • если 1 или 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

Движок Numba

Кроме того, метод .apply() может использовать Numba, если он установлен как необязательная зависимость. Агрегацию apply можно выполнить с помощью Numba, указав аргументы engine='numba' и engine_kwargs (для аргумента raw также должно быть установлено значение True).

Numba будет применяться потенциально в двух случаях:

  • Если func является стандартной функцией Python, движок выполнит JIT переданную функцию. func также может быть JIT-функцией.
  • Движок выполнит 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