Предположим, у меня есть этот фрейм данных
import polars as pl
df = pl.DataFrame({
'item': ['CASH', 'CHECK', 'DEBT', 'CHECK', 'CREDIT', 'CASH'],
'quantity': [100, -20, 0, 10, 0, 0],
'value': [99, 47, None, 90, None, 120],
'value_other': [97, 57, None, 91, None, 110],
'value_other2': [94, 37, None, 93, None, 115],
})
┌────────┬──────────┬───────┬─────────────┬──────────────┐
│ item ┆ quantity ┆ value ┆ value_other ┆ value_other2 │
│ --- ┆ --- ┆ --- ┆ --- ┆ --- │
│ str ┆ i64 ┆ i64 ┆ i64 ┆ i64 │
╞════════╪══════════╪═══════╪═════════════╪══════════════╡
│ CASH ┆ 100 ┆ 99 ┆ 97 ┆ 94 │
│ CHECK ┆ -20 ┆ 47 ┆ 57 ┆ 37 │
│ DEBT ┆ 0 ┆ null ┆ null ┆ null │
│ CHECK ┆ 10 ┆ 90 ┆ 91 ┆ 93 │
│ CREDIT ┆ 0 ┆ null ┆ null ┆ null │
│ CASH ┆ 0 ┆ 120 ┆ 110 ┆ 115 │
└────────┴──────────┴───────┴─────────────┴──────────────┘
Теперь я хочу установить для всех столбцов значений значение 0
для всех строк, где value is null
и quantity == 0
.
Прямо сейчас у меня есть это решение
cols = ['value', 'value_other', 'value_other2']
df = df.with_columns([
pl.when(pl.col('value').is_null() & (pl.col('quantity') == 0))
.then(0)
.otherwise(pl.col(col))
.alias(col)
for col in cols
])
что правильно дает
┌────────┬──────────┬───────┬─────────────┬──────────────┐
│ item ┆ quantity ┆ value ┆ value_other ┆ value_other2 │
│ --- ┆ --- ┆ --- ┆ --- ┆ --- │
│ str ┆ i64 ┆ i64 ┆ i64 ┆ i64 │
╞════════╪══════════╪═══════╪═════════════╪══════════════╡
│ CASH ┆ 100 ┆ 99 ┆ 97 ┆ 94 │
│ CHECK ┆ -20 ┆ 47 ┆ 57 ┆ 37 │
│ DEBT ┆ 0 ┆ 0 ┆ 0 ┆ 0 │
│ CHECK ┆ 10 ┆ 90 ┆ 91 ┆ 93 │
│ CREDIT ┆ 0 ┆ 0 ┆ 0 ┆ 0 │
│ CASH ┆ 0 ┆ 120 ┆ 110 ┆ 115 │
└────────┴──────────┴───────┴─────────────┴──────────────┘
Однако я считаю, что это очень неэффективно, поскольку мое условие when
выполняется для каждого столбца значений. Есть ли способ добиться этого, используя только полярные внутренние функции и без встроенного цикла for?
Примените условие ко всем столбцам одновременно. Также замените alias
на name.keep:
cols = ['value', 'value_other', 'value_other2']
(df.with_columns(
pl.when(pl.col('value').is_null() & (pl.col('quantity') == 0))
.then(0)
.otherwise(pl.col(cols))
.name.keep()
))
Выход:
┌────────┬──────────┬───────┬─────────────┬──────────────┐
│ item ┆ quantity ┆ value ┆ value_other ┆ value_other2 │
│ --- ┆ --- ┆ --- ┆ --- ┆ --- │
│ str ┆ i64 ┆ i64 ┆ i64 ┆ i64 │
╞════════╪══════════╪═══════╪═════════════╪══════════════╡
│ CASH ┆ 100 ┆ 99 ┆ 97 ┆ 94 │
│ CHECK ┆ -20 ┆ 47 ┆ 57 ┆ 37 │
│ DEBT ┆ 0 ┆ 0 ┆ 0 ┆ 0 │
│ CHECK ┆ 10 ┆ 90 ┆ 91 ┆ 93 │
│ CREDIT ┆ 0 ┆ 0 ┆ 0 ┆ 0 │
│ CASH ┆ 0 ┆ 120 ┆ 110 ┆ 115 │
└────────┴──────────┴───────┴─────────────┴──────────────┘
Вы можете передать список имен столбцов в pl.col()
и , когда\то\иначе принимает Expr
, который может содержать несколько столбцов.
cols = ['value', 'value_other', 'value_other2']
df.with_columns(
pl
.when((pl.col.quantity != 0) | pl.col.value.is_not_null())
.then(pl.col(cols))
.otherwise(0)
)
# or
df.with_columns(
pl
.when(pl.col.quantity != 0).then(pl.col(cols))
.when(pl.col.value.is_not_null()).then(pl.col(cols))
.otherwise(0)
)
shape: (6, 5)
┌────────┬──────────┬───────┬─────────────┬──────────────┐
│ item ┆ quantity ┆ value ┆ value_other ┆ value_other2 │
│ --- ┆ --- ┆ --- ┆ --- ┆ --- │
│ str ┆ i64 ┆ i64 ┆ i64 ┆ i64 │
╞════════╪══════════╪═══════╪═════════════╪══════════════╡
│ CASH ┆ 100 ┆ 99 ┆ 97 ┆ 94 │
│ CHECK ┆ -20 ┆ 47 ┆ 57 ┆ 37 │
│ DEBT ┆ 0 ┆ 0 ┆ 0 ┆ 0 │
│ CHECK ┆ 10 ┆ 90 ┆ 91 ┆ 93 │
│ CREDIT ┆ 0 ┆ 0 ┆ 0 ┆ 0 │
│ CASH ┆ 0 ┆ 120 ┆ 110 ┆ 115 │
└────────┴──────────┴───────┴─────────────┴──────────────┘
я хотел явно указать условия для value
и quantity
, а затем установить для всех столбцов значений значение 0
. Есть что-то вроде df.with_columns(pl.col('value').is_null() & (pl.col('quantity') == 0)).then(pl.col(cols).fill(0)).otherwise(pl.col(cols)))
?
Ах, теперь я вижу, я неправильно прочитал требования. Смотрите обновленный ответ.