Python-Polars: как заполнить NA средним значением двух значений между ними?

У меня есть фрейм данных Polars с различными метеостанциями и их данными. Конечная цель – анализ временных рядов. Однако некоторые значения температуры отсутствуют. Чтобы не портить модель, я хочу иметь возможность заполнить пробелы средним значением двух дней по обе стороны от нее. Я хотел бы каким-то образом сгруппировать метеостанцию ​​group_by(), чтобы не брать информацию об одной станции и использовать ее для других станций, отсутствующих в среднем за день. Если есть только одно значение (Начало или Конец периода времени), я хочу использовать то же число, что и день рядом с ним.

Например,

Дата Метеостанция Температура 2024-01-24 А 65 2024-01-25 А Никто 2024-01-26 А 78 2024-01-24 Б Никто 2024-01-25 Б 65 2024-01-26 Б 78

Желаемое решение:

Дата Метеостанция Температура 2024-01-24 А 74 2024-01-25 А 76 2024-01-26 А 78 2024-01-24 Б 65 2024-01-25 Б 65 2024-01-26 Б 78

Как можно заметить, 76 — это среднее значение 74 и 78 за два дня вокруг него, а в случае 24 января 2024 г. B — это 65, поскольку предшествующей даты нет. Я хочу то же самое для обратного (без даты публикации) [пр. если бы это было 27 января 2024 г. Нет для Weather_station B, я бы хотел, чтобы значение было 78]

Вот пример фрейма данных:

data = {
    'Date': ['2024-01-24', '2024-01-25', '2024-01-26', '2024-01-24', '2024-01-25', '2024-01-26'],
    'Weather_Station': ['A', 'A', 'A', 'B', 'B', 'B'],
    'Temp': [74, None, 78, None, 65, 78]
}

Ваша таблица уценок и текстовое описание не соответствуют коду (65 против 74 в первой строке). Я отредактировал это.

mozway 15.05.2024 21:04
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
1
72
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы можете интерполировать , а затем backup_fill /forward_fill над вашей группой:

(pl.DataFrame(data)
   .with_columns(pl.col('Temp').interpolate()
                   .backward_fill().forward_fill()
                   .over('Weather_Station')
                )
)

Выход:

shape: (6, 3)
┌────────────┬─────────────────┬──────┐
│ Date       ┆ Weather_Station ┆ Temp │
│ ---        ┆ ---             ┆ ---  │
│ str        ┆ str             ┆ f64  │
╞════════════╪═════════════════╪══════╡
│ 2024-01-24 ┆ A               ┆ 74.0 │
│ 2024-01-25 ┆ A               ┆ 76.0 │
│ 2024-01-26 ┆ A               ┆ 78.0 │
│ 2024-01-24 ┆ B               ┆ 65.0 │
│ 2024-01-25 ┆ B               ┆ 65.0 │
│ 2024-01-26 ┆ B               ┆ 78.0 │
└────────────┴─────────────────┴──────┘

Альтернативным вариантом, если у вас есть участки NaN, будет получение среднего значения прямого и обратного заполнения:

(pl.DataFrame(data)
   .with_columns((pl.col('Temp').backward_fill()
                 +pl.col('Temp').forward_fill()
                 )
                 .backward_fill().forward_fill()
                 .over('Weather_Station')/2.
                )
)

Выход:

shape: (6, 3)
┌────────────┬─────────────────┬──────┐
│ Date       ┆ Weather_Station ┆ Temp │
│ ---        ┆ ---             ┆ ---  │
│ str        ┆ str             ┆ f64  │
╞════════════╪═════════════════╪══════╡
│ 2024-01-24 ┆ A               ┆ 74.0 │
│ 2024-01-25 ┆ A               ┆ 76.0 │
│ 2024-01-26 ┆ A               ┆ 76.0 │
│ 2024-01-27 ┆ A               ┆ 78.0 │
│ 2024-01-24 ┆ B               ┆ 65.0 │
│ 2024-01-25 ┆ B               ┆ 65.0 │
│ 2024-01-26 ┆ B               ┆ 78.0 │
└────────────┴─────────────────┴──────┘

Альтернативный ввод:

data = {
    'Date': ['2024-01-24', '2024-01-25', '2024-01-26', '2024-01-27', '2024-01-24', '2024-01-25', '2024-01-26'],
    'Weather_Station': ['A', 'A', 'A', 'A', 'B', 'B', 'B'],
    'Temp': [74, None, None, 78, None, 65, 78]
}

Он работает на примере фрейма данных, который я предоставил, и решение довольно простое. Однако, когда я пытаюсь выполнить манипуляцию с моим фреймом данных с 55 тысячами строк, код запускается, но большинство значений остаются равными None. В настоящее время тип данных в столбце — i64. Я не знаю, работают ли в этой операции целые числа и числа с плавающей запятой по-разному. Я также заметил, что у него были проблемы с заготовками. Есть идеи? Спасибо!

ikebeau 15.05.2024 22:06

Можете ли вы проверить альтернативу? Это должно обеспечить одинаковое значение для участков NaN.

mozway 15.05.2024 22:23

Что вы подразумеваете под проверкой альтернативы? Вы имеете в виду сравнение подсчета перед манипуляцией и после манипуляции, чтобы увидеть, есть ли разница? Я рад проверить. Я просто не знаю.

ikebeau 15.05.2024 23:01

Я имел в виду, что обновил свой ответ, добавив альтернативный код;)

mozway 15.05.2024 23:19
import polars as pl
from polars import col

data = {
    'Date': ['2024-01-24', '2024-01-25', '2024-01-26', '2024-01-24', '2024-01-25', '2024-01-26'],
    'Weather_Station': ['A', 'A', 'A', 'B', 'B', 'B'],
    'Temp': [74, None, 78, None, 65, 78]
}
df = pl.DataFrame(data)


print(
    df.with_columns(
        Filled=(
            pl.mean_horizontal(
                col('Temp').forward_fill(), col('Temp').backward_fill(),
            )
            .over('Weather_Station')
        )
    )
)
# shape: (6, 4)
# ┌────────────┬─────────────────┬──────┬────────┐
# │ Date       ┆ Weather_Station ┆ Temp ┆ filled │
# │ ---        ┆ ---             ┆ ---  ┆ ---    │
# │ str        ┆ str             ┆ i64  ┆ f64    │
# ╞════════════╪═════════════════╪══════╪════════╡
# │ 2024-01-24 ┆ A               ┆ 74   ┆ 74.0   │
# │ 2024-01-25 ┆ A               ┆ null ┆ 76.0   │
# │ 2024-01-26 ┆ A               ┆ 78   ┆ 78.0   │
# │ 2024-01-24 ┆ B               ┆ null ┆ 65.0   │
# │ 2024-01-25 ┆ B               ┆ 65   ┆ 65.0   │
# │ 2024-01-26 ┆ B               ┆ 78   ┆ 78.0   │
# └────────────┴─────────────────┴──────┴────────┘

Другие вопросы по теме