Как выполнить join_asof в Polars, рассматривая только назад и соответствуя определенным условиям?

Вопрос или проблема

Я пытаюсь выполнить join_asof в Polars, который будет смотреть только назад во времени, игнорируя совпадения в одной строке. В частности, я хочу, чтобы он находил последнюю строку, где Team и Field совпадают точно, но только если значение Wk меньше, чем значение Wk в текущей строке.

Цель состоит в том, чтобы получить последний GeneralLambda для недавних игр, либо “Гостевой”, либо “Домашний”, исключая текущую игру. Я думал, что лучший способ сделать это – использовать join_asof, но у меня возникают трудности с тем, как сделать так, чтобы он учитывал только прошлые строки и совпадал по обеим Team и Field.

Вот пример DataFrame для иллюстрации:

Сезон Wk Команда Поле GeneralLambda
2024 25 КомандаA Гостевой 2.123456
2024 25 КомандаB Домашний 1.234567
2024 25 КомандаC Гостевой 0.987654
2024 25 КомандаD Домашний 1.345678
2024 25 КомандаE Гостевой 1.456789
2024 26 КомандаA Домашний 1.234567
2024 26 КомандаB Гостевой 1.345678
2024 26 КомандаC Домашний 0.876543
2024 26 КомандаD Гостевой 1.456789
2024 26 КомандаE Домашний 1.567890
2024 27 КомандаA Гостевой 2.278759
2024 27 КомандаB Гостевой 1.103829
2024 27 КомандаC Домашний 0.992563
2024 27 КомандаD Домашний 1.089324
2024 27 КомандаE Домашний 1.074221

Для каждой строки мне нужно объединить её с последней совпадающей строкой, где:

  • Team совпадает,
  • Field совпадает,
  • Wk меньше, чем значение Wk в текущей строке.

Я надеюсь, что DataFrame выглядит так:

Сезон Wk Команда Поле GeneralLambda Prev_GeneralLambda
2024 25 КомандаA Гостевой 2.123456 ALastAwayValue
2024 25 КомандаB Домашний 1.234567 BLastHomeValue
2024 25 КомандаC Гостевой 0.987654 CLastAwayValue
2024 25 КомандаD Домашний 1.345678 DLastHomeValue
2024 25 КомандаE Гостевой 1.456789 ELastAwayValue
2024 26 КомандаA Домашний 1.234567 ALastHomeValue
2024 26 КомандаB Гостевой 1.345678 BLastAwayValue
2024 26 КомандаC Домашний 0.876543 CLastHomeValue
2024 26 КомандаD Гостевой 1.456789 DLastAwayValue
2024 26 КомандаE Домашний 1.567890 ELastHomeValue
2024 27 КомандаA Гостевой 2.278759 2.123456
2024 27 КомандаB Гостевой 1.103829 1.345678
2024 27 КомандаC Домашний 0.992563 0.876543
2024 27 КомандаD Домашний 1.089324 1.345678
2024 27 КомандаE Домашний 1.074221 1.567890

Есть ли способ сделать это в Polars?

(
    df.sort("Wk")
    .with_columns(
        pl.col("GeneralLambda")
        .shift(1)
        .fill_null(pl.col("Team").str.tail(1) + "Last" + pl.col("Field") + "Value")
        .over("Team","Field")
        .alias("Prev_GeneralLambda")
    )
)
shape: (15, 6)
┌────────┬─────┬───────┬───────┬───────────────┬────────────────────┐
│ Сезон  ┆ Wk  ┆ Команда ┆ Поле ┆ GeneralLambda ┆ Prev_GeneralLambda │
│ ---    ┆ --- ┆ ---   ┆ ---   ┆ ---           ┆ ---                │
│ i64    ┆ i64 ┆ str   ┆ str   ┆ f64           ┆ str                │
╞════════╪═════╪═══════╪═══════╪═══════════════╪════════════════════╡
│ 2024   ┆ 25  ┆ КомандаA ┆ Гостевой ┆ 2.123456      ┆ ALastAwayValue     │
│ 2024   ┆ 25  ┆ КомандаB ┆ Домашний ┆ 1.234567      ┆ BLastHomeValue     │
│ 2024   ┆ 25  ┆ КомандаC ┆ Гостевой ┆ 0.987654      ┆ CLastAwayValue     │
│ 2024   ┆ 25  ┆ КомандаD ┆ Домашний ┆ 1.345678      ┆ DLastHomeValue     │
│ 2024   ┆ 25  ┆ КомандаE ┆ Гостевой ┆ 1.456789      ┆ ELastAwayValue     │
│ …      ┆ …   ┆ …     ┆ …     ┆ …             ┆ …                  │
│ 2024   ┆ 27  ┆ КомандаA ┆ Гостевой ┆ 2.278759      ┆ 2.123456           │
│ 2024   ┆ 27  ┆ КомандаB ┆ Гостевой ┆ 1.103829      ┆ 1.345678           │
│ 2024   ┆ 27  ┆ КомандаC ┆ Домашний ┆ 0.992563      ┆ 0.876543           │
│ 2024   ┆ 27  ┆ КомандаD ┆ Домашний ┆ 1.089324      ┆ 1.345678           │
│ 2024   ┆ 27  ┆ КомандаE ┆ Домашний ┆ 1.074221      ┆ 1.56789            │
└────────┴─────┴───────┴───────┴───────────────┴────────────────────┘

Ответ или решение

Для выполнения операции join_asof в библиотеке Polars с учетом только обратных совпадений по заранее определенным условиям, вы можете воспользоваться следующим подходом. Цель состоит в том, чтобы для каждой строки в DataFrame найти последнюю строку, где совпадают значения в столбцах Team и Field, и при этом значение Wk должно быть меньше, чем значение Wk текущей строки.

Шаги реализации

  1. Сортировка DataFrame: Начнем с того, что необходимо отсортировать DataFrame по столбцу Wk, чтобы обеспечить корректный порядок для операции "асинхронного соединения".

  2. Создание нового столбца с предыдущими значениями: Используя метод shift, мы можем создать новый столбец, который будет содержать значение GeneralLambda предыдущей строки для текущей группы Team и Field.

  3. Фильтрация и условное заполнение: Для обеспечения правильности, после создания нового столбца, нужно заполнить его значениями только для тех строк, которые соответствуют условиям.

Пример кода

Вот пример Python-кода, который демонстрирует описанные шаги:

import polars as pl

# Исходный DataFrame
data = {
    "Season": [2024] * 15,
    "Wk": [25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27],
    "Team": ["TeamA", "TeamB", "TeamC", "TeamD", "TeamE", 
             "TeamA", "TeamB", "TeamC", "TeamD", "TeamE",
             "TeamA", "TeamB", "TeamC", "TeamD", "TeamE"],
    "Field": ["Away", "Home", "Away", "Home", "Away", 
              "Home", "Away", "Home", "Away", "Home",
              "Away", "Away", "Home", "Home", "Home"],
    "GeneralLambda": [2.123456, 1.234567, 0.987654, 1.345678, 1.456789, 
                      1.234567, 1.345678, 0.876543, 1.456789, 1.567890, 
                      2.278759, 1.103829, 0.992563, 1.089324, 1.074221],
}

df = pl.DataFrame(data)

# Выполнение join_asof
result = (
    df.sort("Wk")
    .with_columns(
        pl.col("GeneralLambda")
        .shift(1)
        .over("Team", "Field")
        .alias("Prev_GeneralLambda")
    )
    .filter(
        (pl.col("Wk") > pl.col("Wk").shift(1))  # Убедитесь, что Wk меньше
    )
)

print(result)

Описание решения

  1. Сортировка: Убедитесь, что DataFrame отсортирован по Wk перед выполнением join.

  2. Использование shift: Метод shift(1) отбирает значение GeneralLambda из предыдущей строки в рамках группы, что позволяет возвращать только предыдущие значения.

  3. Фильтрация: Фильтруем результаты, чтобы оставить только те строки, где Wk текущей строки больше, обеспечивая таким образом, что мы рассматриваем только предыдущие значения.

Подведение итогов

Данный код эффективно позволяет извлекать значения GeneralLambda для заданных условий, отображая необходимые данные в DataFrame, что облегчает анализ спортивных данных по командам. Использование библиотеки Polars существенно ускоряет операции с большими данными благодаря высокопроизводительным алгоритмам. Убедитесь, что ваша версия библиотеки Polars обновлена до последней, чтобы использовать все доступные функции.

Оцените материал
Добавить комментарий

Капча загружается...