polars.LazyFrame.join_asof
-
Выполняет 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проверяет сортировку только обрабатываемых им строк.
См. также
Примечания
Если задан параметр ‘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 │ └─────────────┴────────────┴────────────┴──────┘
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
© 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