Я пытаюсь выбрать все столбцы DataFrame и выполнить несколько операций над каждым столбцом, используя Polars. Например, я обнаружил, что могу использовать следующий код для подсчета ненулевых значений в каждом столбце:
df.select(pl.col("*").is_not_null().sum()
Однако, когда я пытаюсь объединить несколько операций следующим образом:
(
df
.select(
pl.col("*").is_not_null().sum().alias("foo"),
pl.col("*").is_null().sum().alias("bar")
)
)
Я сталкиваюсь с Duplicated Error.
Кажется, это происходит потому, что Polars пытается выполнить операции, но в конечном итоге использует одни и те же имена столбцов, что вызывает проблему дублирования.
Чтобы обойти эту проблему, я сейчас использую следующий подход:
a = (
df
.select(
pl.col("*").is_null().sum(),
)
.transpose(include_header=True)
.rename(
{"column_0" : "null_count"}
)
)
b = (
df
.select(
pl.col("*").is_not_null().sum(),
)
.transpose(include_header=True)
.rename(
{"column_0" : "not_null_count"}
)
)
a.join(b, how = "left", on = "column")
Моя цель - создать вывод, который выглядит следующим образом:
shape: (8, 3)
┌─────────────┬────────────┬────────────────┐
│ column ┆ null_count ┆ not_null_count │
│ --- ┆ --- ┆ --- │
│ str ┆ u32 ┆ u32 │
╞═════════════╪════════════╪════════════════╡
│ InvoiceNo ┆ 0 ┆ 541909 │
│ StockCode ┆ 0 ┆ 541909 │
│ Description ┆ 1454 ┆ 540455 │
│ Quantity ┆ 0 ┆ 541909 │
│ InvoiceDate ┆ 0 ┆ 541909 │
│ UnitPrice ┆ 0 ┆ 541909 │
│ CustomerID ┆ 135080 ┆ 406829 │
│ Country ┆ 0 ┆ 541909 │
└─────────────┴────────────┴────────────────┘
Во втором коде все столбцы объединены, поэтому вы можете дать им суффикс name.suffix, если вы хотите сохранить все без повторяющихся имен:
(
df
.select(
pl.col("*").is_not_null().sum().name.suffix('_not_null'),
pl.col("*").is_null().sum().name.suffix('_null')
)
)
Выход:
┌───────────┬───────────┬───────────┬───────────┬───┬───────────┬───────────┬───────────┬──────────┐
│ InvoiceNo ┆ StockCode ┆ Descripti ┆ Quantity_ ┆ … ┆ InvoiceDa ┆ UnitPrice ┆ CustomerI ┆ Country_ │
│ _not_null ┆ _not_null ┆ on_not_nu ┆ not_null ┆ ┆ te_null ┆ _null ┆ D_null ┆ null │
│ --- ┆ --- ┆ ll ┆ --- ┆ ┆ --- ┆ --- ┆ --- ┆ --- │
│ u32 ┆ u32 ┆ --- ┆ u32 ┆ ┆ u32 ┆ u32 ┆ u32 ┆ u32 │
│ ┆ ┆ u32 ┆ ┆ ┆ ┆ ┆ ┆ │
╞═══════════╪═══════════╪═══════════╪═══════════╪═══╪═══════════╪═══════════╪═══════════╪══════════╡
│ 90 ┆ 88 ┆ 90 ┆ 87 ┆ … ┆ 14 ┆ 8 ┆ 9 ┆ 8 │
└───────────┴───────────┴───────────┴───────────┴───┴───────────┴───────────┴───────────┴──────────┘
Теперь, учитывая ваш пример, возможно, не имеет особого смысла подсчитывать все значения NULL И все ненулевые значения, поскольку сумма этих двух равна длине DataFrame.
Возможно, вы захотите вычислить один, транспонировать, а затем вычислить второй из исходной длины:
(df.select(pl.col('*').is_null().sum())
.transpose(include_header=True, column_names=['null_count'])
.with_columns(not_null_count=len(df)-pl.col('null_count'))
)
Пример вывода:
┌─────────────┬────────────┬────────────────┐
│ column ┆ null_count ┆ not_null_count │
│ --- ┆ --- ┆ --- │
│ str ┆ u32 ┆ u32 │
╞═════════════╪════════════╪════════════════╡
│ InvoiceNo ┆ 10 ┆ 90 │
│ StockCode ┆ 12 ┆ 88 │
│ Description ┆ 10 ┆ 90 │
│ Quantity ┆ 13 ┆ 87 │
│ InvoiceDate ┆ 14 ┆ 86 │
│ UnitPrice ┆ 8 ┆ 92 │
│ CustomerID ┆ 9 ┆ 91 │
│ Country ┆ 8 ┆ 92 │
└─────────────┴────────────┴────────────────┘
Давайте воспользуемся простым тестовым вводом
df = pl.DataFrame({
"InvoiceNo": [1,2,3],
"StockCode": [1,None,3],
"Description": [None,None,6]
})
Чтобы получить желаемый результат, вы можете использовать
null
, вы можете использовать len(df) - null_count
для вычисления not_null_count
.(
df
.select(pl.all().is_null().sum())
.unpivot(variable_name = "column", value_name = "null_count")
.with_columns(not_null_count = len(df) - pl.col.null_count)
)
┌──────────────┬────────────┬────────────────┐
│ column ┆ null_count ┆ not_null_count │
│ --- ┆ --- ┆ --- │
│ str ┆ u32 ┆ u32 │
╞══════════════╪════════════╪════════════════╡
│ InvoiceNo ┆ 0 ┆ 3 │
│ StockCode ┆ 1 ┆ 2 │
│ Description ┆ 2 ┆ 1 │
└──────────────┴────────────┴────────────────┘
А если вы хотите, чтобы ваш результат имел форму без поворота (например, одна строка и несколько столбцов), вы можете использовать .name.suffix():
(
df
.with_columns(
pl.all().is_null().sum().name.suffix("_is_null"),
pl.all().is_not_null().sum().name.suffix("_is_not_null")
)
)
┌───────────┬───────────┬──────────────┬───────────────┬───┬──────────────┬──────────────┬──────────────┬──────────────┐
│ InvoiceNo ┆ StockCode ┆ Description ┆ InvoiceNo_is_ ┆ … ┆ Description ┆ InvoiceNo_is ┆ StockCode_is ┆ Description │
│ --- ┆ --- ┆ --- ┆ null ┆ ┆ _is_null ┆ _not_null ┆ _not_null ┆ _is_not_null │
│ i64 ┆ i64 ┆ i64 ┆ --- ┆ ┆ --- ┆ --- ┆ --- ┆ --- │
│ ┆ ┆ ┆ u32 ┆ ┆ u32 ┆ u32 ┆ u32 ┆ u32 │
╞═══════════╪═══════════╪══════════════╪═══════════════╪═══╪══════════════╪══════════════╪══════════════╪══════════════╡
│ 1 ┆ 1 ┆ null ┆ 0 ┆ … ┆ 2 ┆ 3 ┆ 2 ┆ 1 │
│ 2 ┆ null ┆ null ┆ 0 ┆ … ┆ 2 ┆ 3 ┆ 2 ┆ 1 │
│ 3 ┆ 3 ┆ 6 ┆ 0 ┆ … ┆ 2 ┆ 3 ┆ 2 ┆ 1 │
└───────────┴───────────┴──────────────┴───────────────┴───┴──────────────┴──────────────┴──────────────┴──────────────┘
честно говоря, не уверен, но в документации есть комментарий This is a very expensive operation. Perhaps you can do it differently.
Хорошо, возможно, когда все типы столбцов разные, чего здесь быть не должно. Приятно знать. Дополнительный комментарий: благодаря вашему редактированию и добавлению name.suffix
наши ответы становятся очень похожими.
Да, я добавил это как дополнение, чтобы показать, почему первоначальная попытка ОП не удалась.
Это довольно близко @RomanPekar, но что, если я попытаюсь получить, например, not_nulls() иmean()? Как я могу отменить поворот новых суффиксов, сохранив имена столбцов оригиналов?
Есть ли особое преимущество в использовании
unpivot
вместоtranspose
, как я это сделал в своем ответе?