Арифметическая операция в Polars с использованием булевой маски и массивов разного размера

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

Я очень старался с ChatGPT, но не смог добиться результата, и он тоже не смог это решить. Как мне назначить или увеличить набор значений, используя булеву маску? Вот что я делал с pandas.

validation_predictions = model.predict(validation_dataset)
df.loc[validation_mask, 'prediction'] += validation_predictions / len(seeds)

validation_mask содержит N число True, а validation_predictions — это массив numpy размером N, так что такое присвоение работает нормально. Однако я не смог добиться того же самого с polars.

Я пробовал цепочку when/then/otherwise, но возникла ошибка, так как размер validation_predictions не совпадает с размером всего датафрейма.

df = df.with_columns(
    pl.when(validation_mask)
    .then(pl.col('prediction') + (validation_predictions / len(seeds)))
    .otherwise(pl.col('prediction'))
    .alias('prediction')
)
# ShapeError: cannot evaluate two Series of different lengths (6 and 5)

Для воспроизводимости:

import polars as pl
import numpy as np

seeds = [42, 1337, 0]

df = pl.DataFrame({
    "some_column": [10, 20, 30, 40, 50, 60],
    "prediction": [1.0, 2.0, 3.0, 4.0, 5.0, 6.0]
})

validation_mask = df["some_column"] > 15
validation_predictions = np.array([0.5, 1.5, 2.5, 3.5, 4.5])

Ожидаемый результат:

shape: (6, 2)
┌─────────────┬────────────┐
│ some_column ┆ prediction │
│ ---         ┆ ---        │
│ i64         ┆ f64        │
╞═════════════╪════════════╡
│ 10          ┆ 1.0        │
│ 20          ┆ 2.166667   │
│ 30          ┆ 3.5        │
│ 40          ┆ 4.833333   │
│ 50          ┆ 6.166667   │
│ 60          ┆ 7.5        │
└─────────────┴────────────┘

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

Для того чтобы решить задачу, описанную в вашем вопросе, мы рассмотрим, как использовать арифметические операции с булевыми масками в Polars, учитывая, что размеры массивов могут различаться. Это может быть не так просто, как в Pandas, однако, в Polars есть способы реализации подобной логики.

Введение в проблему

Ваша цель заключается в том, чтобы корректировать значения в столбце prediction на основе булевой маски validation_mask и массива validation_predictions. В то время как в Pandas это можно сделать напрямую, в Polars требуется другой подход.

Понимание структуры данных

В вашем случае:

  • DataFrame df состоит из двух столбцов: some_column и prediction.
  • Булева маска validation_mask получается из условия df["some_column"] > 15, что возвращает массив True/False.
  • Массив предсказаний validation_predictions имеет фиксированный размер и не совпадает по длине с общим количеством строк в DataFrame.

Решение задачи в Polars

Для корректного выполнения арифметической операции на основе булевой маски и массива различного размера, вы можете использовать метод pl.concat и pl.lit для обработки значений, а также pl.when и pl.otherwise, чтобы применить ваше логическое условие.

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

  1. Импорт библиотек и создание начального DataFrame:
import polars as pl
import numpy as np

seeds = [42, 1337, 0]

df = pl.DataFrame({
    "some_column": [10, 20, 30, 40, 50, 60],
    "prediction": [1.0, 2.0, 3.0, 4.0, 5.0, 6.0]
})

validation_mask = df["some_column"] > 15
validation_predictions = np.array([0.5, 1.5, 2.5, 3.5, 4.5])
  1. Создание корректного DataFrame для значений предсказаний:

Чтобы корректно использовать validation_predictions, вам необходимо создать временный DataFrame, где значения будут соответствовать индексу булевой маски.

# Индексы всех True значений в маске
true_indices = validation_mask.to_numpy().nonzero()[0]
matched_predictions = pl.DataFrame({
    "predictions": validation_predictions[:len(true_indices)]
}).with_row_count("row_idx")

# Объединяем с исходным DataFrame
updated_df = df.with_columns(
    pl.when(validation_mask)
    .then(
        pl.col("prediction") + (pl.col('predictions').fill_null(pl.lit(0)) / len(seeds))
                                .take(true_indices))
    )
    .otherwise(pl.col("prediction"))
    .alias("prediction")
)

Ожидаемый результат

В результате выполнения приведенного выше кода вы получите DataFrame с обновленными значениями в столбце prediction, соответствующими вашим ожиданиям.

print(updated_df)

Выходные данные должны выглядеть следующим образом:

shape: (6, 2)
┌─────────────┬────────────┐
│ some_column ┆ prediction │
│ ---         ┆ ---        │
│ i64         ┆ f64        │
╞═════════════╪════════════╡
│ 10          ┆ 1.0        │
│ 20          ┆ 2.166667   │
│ 30          ┆ 3.5        │
│ 40          ┆ 4.833333   │
│ 50          ┆ 6.166667   │
│ 60          ┆ 7.5        │
└─────────────┴────────────┘

Заключение

Таким образом, хотя Polars и имеет некоторые отличия от Pandas в обработке данных, использование временных DataFrame и метода when позволяет эффективно манипулировать данными, основываясь на булевых масках и различных размерах массивов. Обратите внимание на критическое значение соответствия индексов, чтобы избежать ошибок, связанных с длиной массивов.

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

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