Spec-Zone.ru › Polars

polars.LazyFrame.group_by_dynamic

LazyFrame.group_by_dynamic(
    index_column: IntoExpr,
    *,
    every: str | timedelta,
    period: str | timedelta | None = None,
    offset: str | timedelta | None = None,
    include_boundaries: bool = False,
    closed: ClosedInterval = 'left',
    label: Label = 'left',
    group_by: IntoExpr | Iterable[IntoExpr] | None = None,
    start_by: StartBy = 'window',
) → LazyGroupBy

Группировка по значению времени (или значению индекса типа Int32, Int64).

Вычисляются временные окна, и строки распределяются по окнам. В отличие от обычной группировки, одна строка может входить в несколько групп. По умолчанию окна выглядят так:

  • [start, start + period)
  • [start + every, start + every + period)
  • [start + 2*every, start + 2*every + period)
  • …

где start определяется параметрами start_by, offset, every и самой ранней точкой данных. Подробности см. в описании аргумента start_by.

движок:В памятиЧастично потоковыйЧастично распределённый

Предупреждение

Столбец индекса должен быть отсортирован по возрастанию. Если передан group_by, столбец индекса должен быть отсортирован по возрастанию внутри каждой группы.

Изменено в версии 0.20.14: Параметр by был переименован в group_by.

Параметры:
index_column

Столбец, используемый для группировки по временному окну. Обычно имеет тип Date/Datetime. Этот столбец должен быть отсортирован по возрастанию (или, если указано group_by, он должен быть отсортирован по возрастанию внутри каждой группы).

При динамической группировке по индексам тип данных должен быть одним из {Int32, Int64}. Обратите внимание: Int32 временно приводится к Int64, поэтому, если важна производительность, используйте столбец Int64.

every

интервал окна

period

длина окна; если значение равно None, она будет равна «every»

offset

смещение окна; не применяется, если start_by равно ‘datapoint’. По умолчанию равно нулю.

include_boundaries

Добавить нижнюю и верхнюю границы окна в столбцы “_lower_boundary” и “_upper_boundary”. Это повлияет на производительность, так как усложнит распараллеливание.

closed{‘left’, ‘right’, ‘both’, ‘none’}

Определяет, какие стороны временного интервала являются закрытыми (включительными).

label{‘left’, ‘right’, ‘datapoint’}

Определяет, какую метку использовать для окна:

  • ‘left’: нижняя граница окна
  • ‘right’: верхняя граница окна
  • ‘datapoint’: первое значение столбца индекса в данном окне. Если метка не должна совпадать с одной из границ, выберите этот вариант для максимальной производительности
group_by

Также группировать по этому столбцу или этим столбцам

start_by{‘window’, ‘datapoint’, ‘monday’, ‘tuesday’, ‘wednesday’, ‘thursday’, ‘friday’, ‘saturday’, ‘sunday’}

Стратегия определения начала первого окна.

  • ‘window’: начать с самой ранней временной метки, округлить её с помощью every, а затем добавить offset. Обратите внимание: недельные окна начинаются в понедельник.
  • ‘datapoint’: начать с первой встреченной точки данных.
  • день недели (применяется, только если every содержит 'w'):

    • ‘monday’: начать окно с понедельника перед первой точкой данных.
    • ‘tuesday’: начать окно со вторника перед первой точкой данных.
    • …
    • ‘sunday’: начать окно с воскресенья перед первой точкой данных.

    Затем полученное окно сдвигается назад, пока самая ранняя точка данных не окажется внутри него или перед ним.

Возвращает:
LazyGroupBy

Объект, для которого можно вызвать .agg, чтобы выполнить агрегацию по группам. Результат будет отсортирован по index_column (обратите внимание: если переданы столбцы group_by, сортировка будет выполнена только внутри каждой группы).

См. также

rolling

Примечания

  1. Если вы переходите с pandas, то

    # polars
    df.group_by_dynamic("ts", every="1d").agg(pl.col("value").sum())
    

    эквивалентно

    # pandas
    df.set_index("ts").resample("D")["value"].sum().reset_index()
    

    однако, в отличие от pandas, polars не добавляет дополнительные строки для пустых окон. Если требуется, чтобы index_column имели равномерный шаг, объедините эту операцию с DataFrame.upsample().

  2. Аргументы every, period и offset задаются с помощью следующего строкового формата:

    • 1ns (1 наносекунда)
    • 1us (1 микросекунда)
    • 1ms (1 миллисекунда)
    • 1s (1 секунда)
    • 1m (1 минута)
    • 1h (1 час)
    • 1d (1 календарный день)
    • 1w (1 календарная неделя)
    • 1mo (1 календарный месяц)
    • 1q (1 календарный квартал)
    • 1y (1 календарный год)
    • 1i (1 единица индекса)

    Их можно объединять (кроме every): “3d12h4m25s” # 3 дня, 12 часов, 4 минуты и 25 секунд

    Под «календарным днём» понимается соответствующее время следующего дня (который может длиться не 24 часа из-за перехода на летнее время). То же относится к «календарной неделе», «календарному месяцу», «календарному кварталу» и «календарному году».

    При group_by_dynamic по целочисленному столбцу окна задаются следующим образом:

    • “1i” # длина 1
    • “10i” # длина 10

Примеры

>>> from datetime import datetime
>>> lf = pl.LazyFrame(
...     {
...         "time": pl.datetime_range(
...             start=datetime(2021, 12, 16),
...             end=datetime(2021, 12, 16, 3),
...             interval="30m",
...             eager=True,
...         ),
...         "n": range(7),
...     }
... )
>>> lf.collect()
shape: (7, 2)
┌─────────────────────┬─────┐
│ time                ┆ n   │
│ ---                 ┆ --- │
│ datetime[μs]        ┆ i64 │
╞═════════════════════╪═════╡
│ 2021-12-16 00:00:00 ┆ 0   │
│ 2021-12-16 00:30:00 ┆ 1   │
│ 2021-12-16 01:00:00 ┆ 2   │
│ 2021-12-16 01:30:00 ┆ 3   │
│ 2021-12-16 02:00:00 ┆ 4   │
│ 2021-12-16 02:30:00 ┆ 5   │
│ 2021-12-16 03:00:00 ┆ 6   │
└─────────────────────┴─────┘

Группировка по окнам длительностью 1 час.

>>> lf.group_by_dynamic("time", every="1h", closed="right").agg(
...     pl.col("n")
... ).collect()
shape: (4, 2)
┌─────────────────────┬───────────┐
│ time                ┆ n         │
│ ---                 ┆ ---       │
│ datetime[μs]        ┆ list[i64] │
╞═════════════════════╪═══════════╡
│ 2021-12-15 23:00:00 ┆ [0]       │
│ 2021-12-16 00:00:00 ┆ [1, 2]    │
│ 2021-12-16 01:00:00 ┆ [3, 4]    │
│ 2021-12-16 02:00:00 ┆ [5, 6]    │
└─────────────────────┴───────────┘

Границы окна также можно добавить в результат агрегации

>>> lf.group_by_dynamic(
...     "time", every="1h", include_boundaries=True, closed="right"
... ).agg(pl.col("n").mean()).collect()
shape: (4, 4)
┌─────────────────────┬─────────────────────┬─────────────────────┬─────┐
│ _lower_boundary     ┆ _upper_boundary     ┆ time                ┆ n   │
│ ---                 ┆ ---                 ┆ ---                 ┆ --- │
│ datetime[μs]        ┆ datetime[μs]        ┆ datetime[μs]        ┆ f64 │
╞═════════════════════╪═════════════════════╪═════════════════════╪═════╡
│ 2021-12-15 23:00:00 ┆ 2021-12-16 00:00:00 ┆ 2021-12-15 23:00:00 ┆ 0.0 │
│ 2021-12-16 00:00:00 ┆ 2021-12-16 01:00:00 ┆ 2021-12-16 00:00:00 ┆ 1.5 │
│ 2021-12-16 01:00:00 ┆ 2021-12-16 02:00:00 ┆ 2021-12-16 01:00:00 ┆ 3.5 │
│ 2021-12-16 02:00:00 ┆ 2021-12-16 03:00:00 ┆ 2021-12-16 02:00:00 ┆ 5.5 │
└─────────────────────┴─────────────────────┴─────────────────────┴─────┘

При closed=”left” окно не включает правый конец интервала: [lower_bound, upper_bound)

>>> lf.group_by_dynamic("time", every="1h", closed="left").agg(
...     pl.col("n")
... ).collect()
shape: (4, 2)
┌─────────────────────┬───────────┐
│ time                ┆ n         │
│ ---                 ┆ ---       │
│ datetime[μs]        ┆ list[i64] │
╞═════════════════════╪═══════════╡
│ 2021-12-16 00:00:00 ┆ [0, 1]    │
│ 2021-12-16 01:00:00 ┆ [2, 3]    │
│ 2021-12-16 02:00:00 ┆ [4, 5]    │
│ 2021-12-16 03:00:00 ┆ [6]       │
└─────────────────────┴───────────┘

При closed=”both” значения времени на границах окна входят в 2 группы.

>>> lf.group_by_dynamic("time", every="1h", closed="both").agg(
...     pl.col("n")
... ).collect()
shape: (4, 2)
┌─────────────────────┬───────────┐
│ time                ┆ n         │
│ ---                 ┆ ---       │
│ datetime[μs]        ┆ list[i64] │
╞═════════════════════╪═══════════╡
│ 2021-12-16 00:00:00 ┆ [0, 1, 2] │
│ 2021-12-16 01:00:00 ┆ [2, 3, 4] │
│ 2021-12-16 02:00:00 ┆ [4, 5, 6] │
│ 2021-12-16 03:00:00 ┆ [6]       │
└─────────────────────┴───────────┘

Динамическую группировку также можно сочетать с группировкой по обычным ключам

>>> lf = lf.with_columns(groups=pl.Series(["a", "a", "a", "b", "b", "a", "a"]))
>>> lf.collect()
shape: (7, 3)
┌─────────────────────┬─────┬────────┐
│ time                ┆ n   ┆ groups │
│ ---                 ┆ --- ┆ ---    │
│ datetime[μs]        ┆ i64 ┆ str    │
╞═════════════════════╪═════╪════════╡
│ 2021-12-16 00:00:00 ┆ 0   ┆ a      │
│ 2021-12-16 00:30:00 ┆ 1   ┆ a      │
│ 2021-12-16 01:00:00 ┆ 2   ┆ a      │
│ 2021-12-16 01:30:00 ┆ 3   ┆ b      │
│ 2021-12-16 02:00:00 ┆ 4   ┆ b      │
│ 2021-12-16 02:30:00 ┆ 5   ┆ a      │
│ 2021-12-16 03:00:00 ┆ 6   ┆ a      │
└─────────────────────┴─────┴────────┘
>>> lf.group_by_dynamic(
...     "time",
...     every="1h",
...     closed="both",
...     group_by="groups",
...     include_boundaries=True,
... ).agg(pl.col("n")).collect()
shape: (6, 5)
┌────────┬─────────────────────┬─────────────────────┬─────────────────────┬───────────┐
│ groups ┆ _lower_boundary     ┆ _upper_boundary     ┆ time                ┆ n         │
│ ---    ┆ ---                 ┆ ---                 ┆ ---                 ┆ ---       │
│ str    ┆ datetime[μs]        ┆ datetime[μs]        ┆ datetime[μs]        ┆ list[i64] │
╞════════╪═════════════════════╪═════════════════════╪═════════════════════╪═══════════╡
│ a      ┆ 2021-12-16 00:00:00 ┆ 2021-12-16 01:00:00 ┆ 2021-12-16 00:00:00 ┆ [0, 1, 2] │
│ a      ┆ 2021-12-16 01:00:00 ┆ 2021-12-16 02:00:00 ┆ 2021-12-16 01:00:00 ┆ [2]       │
│ a      ┆ 2021-12-16 02:00:00 ┆ 2021-12-16 03:00:00 ┆ 2021-12-16 02:00:00 ┆ [5, 6]    │
│ a      ┆ 2021-12-16 03:00:00 ┆ 2021-12-16 04:00:00 ┆ 2021-12-16 03:00:00 ┆ [6]       │
│ b      ┆ 2021-12-16 01:00:00 ┆ 2021-12-16 02:00:00 ┆ 2021-12-16 01:00:00 ┆ [3, 4]    │
│ b      ┆ 2021-12-16 02:00:00 ┆ 2021-12-16 03:00:00 ┆ 2021-12-16 02:00:00 ┆ [4]       │
└────────┴─────────────────────┴─────────────────────┴─────────────────────┴───────────┘

Динамическая группировка по столбцу индекса

>>> lf = pl.LazyFrame(
...     {
...         "idx": pl.int_range(0, 6, eager=True),
...         "A": ["A", "A", "B", "B", "B", "C"],
...     }
... )
>>> lf.group_by_dynamic(
...     "idx",
...     every="2i",
...     period="3i",
...     include_boundaries=True,
...     closed="right",
... ).agg(pl.col("A").alias("A_agg_list")).collect()
shape: (4, 4)
┌─────────────────┬─────────────────┬─────┬─────────────────┐
│ _lower_boundary ┆ _upper_boundary ┆ idx ┆ A_agg_list      │
│ ---             ┆ ---             ┆ --- ┆ ---             │
│ i64             ┆ i64             ┆ i64 ┆ list[str]       │
╞═════════════════╪═════════════════╪═════╪═════════════════╡
│ -2              ┆ 1               ┆ -2  ┆ ["A", "A"]      │
│ 0               ┆ 3               ┆ 0   ┆ ["A", "B", "B"] │
│ 2               ┆ 5               ┆ 2   ┆ ["B", "B", "C"] │
│ 4               ┆ 7               ┆ 4   ┆ ["C"]           │
└─────────────────┴─────────────────┴─────┴─────────────────┘

© 2020 Ritchie Vink
© 2022 Polars contributors
Licensed under the MIT License.
https://docs.pola.rs/api/python/stable/reference/lazyframe/api/polars.LazyFrame.group_by_dynamic.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API