Spec-Zone.ru › Polars

polars.LazyFrame.join_asof

LazyFrame.join_asof(
    other: LazyFrame,
    *,
    left_on: str | None | Expr = None,
    right_on: str | None | Expr = None,
    on: str | None | Expr = None,
    by_left: str | Sequence[str] | None = None,
    by_right: str | Sequence[str] | None = None,
    by: str | Sequence[str] | None = None,
    strategy: AsofJoinStrategy = 'backward',
    suffix: str = '_right',
    tolerance: str | int | float | timedelta | None = None,
    allow_parallel: bool = True,
    force_parallel: bool = False,
    coalesce: bool = True,
    allow_exact_matches: bool = True,
    check_sortedness: bool = True,
) → LazyFrame

Выполняет asof-соединение.

Оно похоже на левое соединение, но вместо равенства ключей выполняется сопоставление по ближайшему ключу.

Оба DataFrame должны быть отсортированы по ключу on (в каждой группе by, если она указана).

Для каждой строки левого DataFrame:

  • При поиске «назад» выбирается последняя строка правого DataFrame, ключ ‘on’ которой меньше или равен ключу левого DataFrame.
  • При поиске «вперёд» выбирается первая строка правого DataFrame, ключ ‘on’ которой больше или равен ключу левого DataFrame.

    При поиске «ближайшего» выбирается последняя строка правого DataFrame, значение которой ближе всего к ключу левого DataFrame. Строковые ключи для поиска ближайшего значения пока не поддерживаются.

По умолчанию используется поиск «назад».

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

Ленивый DataFrame для соединения.

left_on

Столбец соединения левого DataFrame.

right_on

Столбец соединения правого DataFrame.

on

Столбец соединения обоих DataFrame. Если задан, left_on и right_on должны быть None.

by_left

Сначала выполнить соединение по этим столбцам, а затем asof-соединение.

by_right

Сначала выполнить соединение по этим столбцам, а затем asof-соединение.

by

Сначала выполнить соединение по этим столбцам, а затем asof-соединение.

strategy{‘backward’, ‘forward’, ‘nearest’}

Стратегия соединения.

suffix

Суффикс, добавляемый к столбцам с повторяющимися именами.

tolerance

Числовой допуск. Если задать этот параметр, соединение будет выполнено только в том случае, если расстояние между близкими ключами не превышает указанного значения. Для asof-соединения по столбцам типа “Date”, “Datetime”, “Duration” или “Time” используйте объект datetime.timedelta или строку в следующем формате:

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

Или объедините значения: “3d12h4m25s” # 3 дня, 12 часов, 4 минуты и 25 секунд

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

allow_parallel

Разрешить физическому плану при необходимости параллельно вычислять оба DataFrame вплоть до операции соединения.

force_parallel

Заставить физический план вычислять оба DataFrame параллельно вплоть до операции соединения.

coalesce

Поведение объединения (слияние столбцов on / left_on / right_on):

  • True: -> всегда объединять столбцы соединения.
  • False: -> никогда не объединять столбцы соединения.

Обратите внимание: при соединении по любым выражениям, кроме col, объединение столбцов отключается.

allow_exact_matches

Допускаются ли точные совпадения в качестве предикатов соединения.

  • If True, allow matching with the same on value

    (то есть меньше или равно / больше или равно)

  • If False, don’t match the same on value

    (то есть строго меньше / строго больше).

check_sortedness

Проверять, отсортированы ли ключи asof-соединения. Если ключи не отсортированы, Polars выдаст ошибку. В настоящее время движок in-memory не может проверить сортировку, если заданы группы ‘by’. Движок streaming проверяет сортировку только обрабатываемых им строк.

См. также

join
join_where

Примечания

Если задан параметр ‘by’, реализация вычисляет asof-соединение для всех групп одновременно. При большом количестве групп это может привести к значительному расходу памяти.

Эту проблему можно смягчить, отсортировав оба входных LazyFrame по ключам ‘by’ (с помощью .sort() или используя .set_sorted(), если столбцы уже отсортированы) перед выполнением операции соединения, а затем собрав результаты с помощью потокового движка. Например:

>>> # Compute streaming asof join with 'by' groups
>>> result = (
...     left.sort("by", "on").join_asof(  # Sort left manually
...         right.set_sorted("by", "on"),  # Set right as already sorted
...     )
... ).collect(streaming=True)  

Примеры

>>> from datetime import date
>>> gdp = pl.LazyFrame(
...     {
...         "date": pl.date_range(
...             date(2016, 1, 1),
...             date(2020, 1, 1),
...             "1y",
...             eager=True,
...         ),
...         "gdp": [4164, 4411, 4566, 4696, 4827],
...     }
... )
>>> gdp.collect()
shape: (5, 2)
┌────────────┬──────┐
│ date       ┆ gdp  │
│ ---        ┆ ---  │
│ date       ┆ i64  │
╞════════════╪══════╡
│ 2016-01-01 ┆ 4164 │
│ 2017-01-01 ┆ 4411 │
│ 2018-01-01 ┆ 4566 │
│ 2019-01-01 ┆ 4696 │
│ 2020-01-01 ┆ 4827 │
└────────────┴──────┘
>>> population = pl.LazyFrame(
...     {
...         "date": [date(2016, 3, 1), date(2018, 8, 1), date(2019, 1, 1)],
...         "population": [82.19, 82.66, 83.12],
...     }
... ).sort("date")
>>> population.collect()
shape: (3, 2)
┌────────────┬────────────┐
│ date       ┆ population │
│ ---        ┆ ---        │
│ date       ┆ f64        │
╞════════════╪════════════╡
│ 2016-03-01 ┆ 82.19      │
│ 2018-08-01 ┆ 82.66      │
│ 2019-01-01 ┆ 83.12      │
└────────────┴────────────┘

Обратите внимание, что даты не совсем совпадают. Если соединить их с помощью join_asof и strategy='backward', каждая дата из population, для которой нет точного совпадения, будет сопоставлена с ближайшей более ранней датой из gdp:

>>> population.join_asof(gdp, on="date", strategy="backward").collect()
shape: (3, 3)
┌────────────┬────────────┬──────┐
│ date       ┆ population ┆ gdp  │
│ ---        ┆ ---        ┆ ---  │
│ date       ┆ f64        ┆ i64  │
╞════════════╪════════════╪══════╡
│ 2016-03-01 ┆ 82.19      ┆ 4164 │
│ 2018-08-01 ┆ 82.66      ┆ 4566 │
│ 2019-01-01 ┆ 83.12      ┆ 4696 │
└────────────┴────────────┴──────┘

Обратите внимание:

  • дата 2016-03-01 из population сопоставлена с 2016-01-01 из gdp;
  • дата 2018-08-01 из population сопоставлена с 2018-01-01 из gdp.

Это можно проверить, передав coalesce=False:

>>> population.join_asof(
...     gdp, on="date", strategy="backward", coalesce=False
... ).collect()
shape: (3, 4)
┌────────────┬────────────┬────────────┬──────┐
│ date       ┆ population ┆ date_right ┆ gdp  │
│ ---        ┆ ---        ┆ ---        ┆ ---  │
│ date       ┆ f64        ┆ date       ┆ i64  │
╞════════════╪════════════╪════════════╪══════╡
│ 2016-03-01 ┆ 82.19      ┆ 2016-01-01 ┆ 4164 │
│ 2018-08-01 ┆ 82.66      ┆ 2018-01-01 ┆ 4566 │
│ 2019-01-01 ┆ 83.12      ┆ 2019-01-01 ┆ 4696 │
└────────────┴────────────┴────────────┴──────┘

Если вместо этого использовать strategy='forward', каждая дата из population, для которой нет точного совпадения, будет сопоставлена с ближайшей более поздней датой из gdp:

>>> population.join_asof(gdp, on="date", strategy="forward").collect()
shape: (3, 3)
┌────────────┬────────────┬──────┐
│ date       ┆ population ┆ gdp  │
│ ---        ┆ ---        ┆ ---  │
│ date       ┆ f64        ┆ i64  │
╞════════════╪════════════╪══════╡
│ 2016-03-01 ┆ 82.19      ┆ 4411 │
│ 2018-08-01 ┆ 82.66      ┆ 4696 │
│ 2019-01-01 ┆ 83.12      ┆ 4696 │
└────────────┴────────────┴──────┘

Обратите внимание:

  • дата 2016-03-01 из population сопоставлена с 2017-01-01 из gdp;
  • дата 2018-08-01 из population сопоставлена с 2019-01-01 из gdp.

Наконец, strategy='nearest' даёт результат, сочетающий два предыдущих: каждая дата из population, для которой нет точного совпадения, сопоставляется с ближайшей датой из gdp независимо от того, раньше она или позже:

>>> population.join_asof(gdp, on="date", strategy="nearest").collect()
shape: (3, 3)
┌────────────┬────────────┬──────┐
│ date       ┆ population ┆ gdp  │
│ ---        ┆ ---        ┆ ---  │
│ date       ┆ f64        ┆ i64  │
╞════════════╪════════════╪══════╡
│ 2016-03-01 ┆ 82.19      ┆ 4164 │
│ 2018-08-01 ┆ 82.66      ┆ 4696 │
│ 2019-01-01 ┆ 83.12      ┆ 4696 │
└────────────┴────────────┴──────┘

Обратите внимание:

  • дата 2016-03-01 из population сопоставлена с 2016-01-01 из gdp;
  • дата 2018-08-01 из population сопоставлена с 2019-01-01 из gdp.

Аргумент by позволяет сначала выполнить соединение по другому столбцу, а затем — asof-соединение. В этом примере сначала выполняется соединение по country, а затем asof-соединение по дате, как и выше.

>>> gdp_dates = pl.date_range(  # fmt: skip
...     date(2016, 1, 1), date(2020, 1, 1), "1y", eager=True
... )
>>> gdp2 = pl.LazyFrame(
...     {
...         "country": ["Germany"] * 5 + ["Netherlands"] * 5,
...         "date": pl.concat([gdp_dates, gdp_dates]),
...         "gdp": [4164, 4411, 4566, 4696, 4827, 784, 833, 914, 910, 909],
...     }
... ).sort("country", "date")
>>>
>>> gdp2.collect()
shape: (10, 3)
┌─────────────┬────────────┬──────┐
│ country     ┆ date       ┆ gdp  │
│ ---         ┆ ---        ┆ ---  │
│ str         ┆ date       ┆ i64  │
╞═════════════╪════════════╪══════╡
│ Germany     ┆ 2016-01-01 ┆ 4164 │
│ Germany     ┆ 2017-01-01 ┆ 4411 │
│ Germany     ┆ 2018-01-01 ┆ 4566 │
│ Germany     ┆ 2019-01-01 ┆ 4696 │
│ Germany     ┆ 2020-01-01 ┆ 4827 │
│ Netherlands ┆ 2016-01-01 ┆ 784  │
│ Netherlands ┆ 2017-01-01 ┆ 833  │
│ Netherlands ┆ 2018-01-01 ┆ 914  │
│ Netherlands ┆ 2019-01-01 ┆ 910  │
│ Netherlands ┆ 2020-01-01 ┆ 909  │
└─────────────┴────────────┴──────┘
>>> pop2 = pl.LazyFrame(
...     {
...         "country": ["Germany"] * 3 + ["Netherlands"] * 3,
...         "date": [
...             date(2016, 3, 1),
...             date(2018, 8, 1),
...             date(2019, 1, 1),
...             date(2016, 3, 1),
...             date(2018, 8, 1),
...             date(2019, 1, 1),
...         ],
...         "population": [82.19, 82.66, 83.12, 17.11, 17.32, 17.40],
...     }
... ).sort("country", "date")
>>>
>>> pop2.collect()
shape: (6, 3)
┌─────────────┬────────────┬────────────┐
│ country     ┆ date       ┆ population │
│ ---         ┆ ---        ┆ ---        │
│ str         ┆ date       ┆ f64        │
╞═════════════╪════════════╪════════════╡
│ Germany     ┆ 2016-03-01 ┆ 82.19      │
│ Germany     ┆ 2018-08-01 ┆ 82.66      │
│ Germany     ┆ 2019-01-01 ┆ 83.12      │
│ Netherlands ┆ 2016-03-01 ┆ 17.11      │
│ Netherlands ┆ 2018-08-01 ┆ 17.32      │
│ Netherlands ┆ 2019-01-01 ┆ 17.4       │
└─────────────┴────────────┴────────────┘
>>> pop2.join_asof(gdp2, by="country", on="date", strategy="nearest").collect()
shape: (6, 4)
┌─────────────┬────────────┬────────────┬──────┐
│ country     ┆ date       ┆ population ┆ gdp  │
│ ---         ┆ ---        ┆ ---        ┆ ---  │
│ str         ┆ date       ┆ f64        ┆ i64  │
╞═════════════╪════════════╪════════════╪══════╡
│ Germany     ┆ 2016-03-01 ┆ 82.19      ┆ 4164 │
│ Germany     ┆ 2018-08-01 ┆ 82.66      ┆ 4696 │
│ Germany     ┆ 2019-01-01 ┆ 83.12      ┆ 4696 │
│ Netherlands ┆ 2016-03-01 ┆ 17.11      ┆ 784  │
│ Netherlands ┆ 2018-08-01 ┆ 17.32      ┆ 910  │
│ Netherlands ┆ 2019-01-01 ┆ 17.4       ┆ 910  │
└─────────────┴────────────┴────────────┴──────┘

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

Spec-Zone.ru

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