Как заменить значения, превышающие пороговое значение, на ноль в определенных столбцах DataFrame Polars?
Я пытаюсь заменить любое значение, превышающее определенное условие (например, 20), на ноль для всех числовых столбцов в DataFrame Polars, исключая столбец с датой.
Моя попытка с использованием with_columns обнуляет всю строку:
df.with_columns(
pl.when(pl.any_horizontal(pl.col(pl.Float32) > 20))
.then(0)
.otherwise(pl.col(pl.Float32))
)
Моя неработающая попытка с использованием select:
df=df.select(
pl.col("date"),
pl.when(pl.col(pl.Float32) > 20).then(0))
В Pandas это было бы просто:
df.where(df>2, 0)
Как правильно добиться этого в Polars?
Чтобы заменить значения, превышающие пороговое значение, на ноль в определенных столбцах DataFrame Polars, необходимо использовать выбор столбцов с условной логикой. Ключ заключается в применении преобразования только к числовым столбцам, сохраняя нечисловые столбцы, такие как даты.
Вот правильный подход с использованием нескольких методов:
import polars as pl
# Метод 1: Использование clip() - наиболее эффективно для простого порогового значения
df_capped = df.with_columns(
pl.col(pl.Float32 | pl.Float64).clip(upper_bound=20)
)
# Метод 2: Использование when().then() с выбором столбцов
df_conditioned = df.with_columns(
pl.when(pl.col(pl.Float32 | pl.Float64) > 20)
.then(0)
.otherwise(pl.col(pl.Float32 | pl.Float64))
.keep_name()
)
# Метод 3: Использование set() с булевой маской (из SparkByExamples)
df_masked = df.with_columns(
pl.col(pl.Float32 | pl.Float64).set(pl.col(pl.Float32 | pl.Float64) > 20, 0)
)
Содержание
- Понимание выбора столбцов
- Эффективные методы замены пороговых значений
- Обработка нескольких числовых типов
- Сохранение нечисловых столбцов
- Сравнение производительности
- Практические примеры
Понимание выбора столбцов
Polars использует мощные шаблоны выбора столбцов. Выражение pl.col(pl.Float32 | pl.Float64) выбирает только столбцы с плавающей точкой, что идеально подходит для вашего случая использования. Вы также можете использовать pl.col(pl.NUMERIC_TYPES) для включения всех числовых типов.
# Выбор всех числовых столбцов
numeric_cols = pl.col(pl.INTEGER_DTYPES | pl.FLOAT_DTYPES)
# Исключение определенных столбцов
numeric_cols_only = pl.col(pl.NUMERIC_TYPES).exclude("date")
Эффективные методы замены пороговых значений
1. Использование clip() - Наиболее производительный
Функция clip() является наиболее эффективным способом замены значений выше/ниже пороговых значений:
df_capped = df.with_columns(
pl.col(pl.NUMERIC_TYPES)
.clip(lower_bound=0, upper_bound=20) # Заменяет значения > 20 на 20
)
2. Использование when().then() - Наиболее гибкий
Для сложной условной логики:
df_conditioned = df.with_columns(
pl.when(pl.col(pl.NUMERIC_TYPES) > 20)
.then(0)
.otherwise(pl.col(pl.NUMERIC_TYPES))
.name.keep()
)
3. Использование set() с булевой маской
Из документации SparkByExamples:
df_masked = df.with_columns(
pl.col(pl.NUMERIC_TYPES).set(
pl.col(pl.NUMERIC_TYPES) > 20,
0
)
)
Обработка нескольких числовых типов
Чтобы убедиться, что все числовые столбцы обрабатываются, используйте комплексный селектор числовых типов:
# Включение всех числовых типов
df_processed = df.with_columns(
pl.when(pl.col(pl.NUMERIC_TYPES) > 20)
.then(0)
.otherwise(pl.col(pl.NUMERIC_TYPES))
.name.keep()
)
Если необходимо исключить определенные столбцы, такие как даты:
df_processed = df.with_columns(
pl.when(pl.col(pl.NUMERIC_TYPES).exclude("date") > 20)
.then(0)
.otherwise(pl.col(pl.NUMERIC_TYPES).exclude("date"))
.name.keep()
)
Сохранение нечисловых столбцов
Метод with_columns() автоматически сохраняет все столбцы, которые не были явно изменены. Именно поэтому ваша предыдущая попытка с select() потерпела неудачу - она создала новый DataFrame только с указанными столбцами.
Вот полное решение, которое сохраняет все столбцы:
# Заменяет значения > 20 на 0 во всех числовых столбцах, сохраняя остальные без изменений
df_final = df.with_columns(
pl.when(pl.col(pl.NUMERIC_TYPES) > 20)
.then(0)
.otherwise(pl.col(pl.NUMERIC_TYPES))
.name.keep()
)
Сравнение производительности
На основе результатов исследования:
clip()является самым быстрым для простых операций пороговых значенийwhen().then()более гибкий, но немного медленнееset()с маской имеет промежуточную производительность
Для большинства случаев использования рекомендуется clip(), когда вам просто нужно ограничить значения порогом.
Практические примеры
Пример 1: Базовая замена пороговых значений
import polars as pl
# Создание примера DataFrame
df = pl.DataFrame({
"date": ["2023-01-01", "2023-01-02", "2023-01-03"],
"sales": [15, 25, 30],
"inventory": [100, 150, 200],
"temperature": [18.5, 22.3, 25.1]
})
# Замена значений > 20 на 0
df_result = df.with_columns(
pl.when(pl.col(pl.NUMERIC_TYPES) > 20)
.then(0)
.otherwise(pl.col(pl.NUMERIC_TYPES))
.name.keep()
)
print(df_result)
Пример 2: Использование разных пороговых значений
# Замена sales > 25 на 0, inventory > 120 на 0, temperature > 22 на 0
df_result = df.with_columns([
pl.when(pl.col("sales") > 25).then(0).otherwise(pl.col("sales")).alias("sales"),
pl.when(pl.col("inventory") > 120).then(0).otherwise(pl.col("inventory")).alias("inventory"),
pl.when(pl.col("temperature") > 22).then(0).otherwise(pl.col("temperature")).alias("temperature")
])
Ключевое понимание заключается в том, что выражения выбора столбцов Polars в сочетании с with_columns() позволяют применять преобразования выборочно, сохраняя структуру исходного DataFrame. Этот подход как эффективен, так и удобочитаем для вашего случая использования.
Источники
- Документация Polars Expressions - Выбор столбцов
- SparkByExamples - Замена значений в Polars Series
- Документация Polars Expr.replace
- StackOverflow - Polars Замена значений, превышающих максимум другого Polars DataFrame
- GitHub Issue Polars - Добавление функциональности замены
Заключение
Чтобы заменить значения, превышающие пороговое значение, на ноль в определенных столбцах DataFrame Polars:
- Используйте
with_columns()для сохранения всех столбцов при применении преобразований - Выбирайте числовые столбцы с помощью
pl.col(pl.NUMERIC_TYPES)или определенных типов - Применяйте логику пороговых значений с помощью
clip(),when().then()илиset()с булевыми масками - Метод
clip()обеспечивает лучшую производительность для простых операций пороговых значений - Всегда тестируйте с вашими конкретными типами данных и именами столбцов
Наиболее эффективное решение для вашего случая использования:
df_final = df.with_columns(
pl.col(pl.NUMERIC_TYPES).clip(upper_bound=20)
)
Этот подход автоматически заменит все значения, превышающие 20, на 20 во всех числовых столбцах, сохраняя нечисловые столбцы, такие как даты.