Логические операции по столбцам и строкам в Polars DataFrame

В Pandas можно выполнять логические операции над логическими DataFrames с помощью методов all и any, предоставляя аргумент axis. Например:

import pandas as pd

data = dict(A=["a","b","?"], B=["d","?","f"])
pd_df = pd.DataFrame(data)

Например, чтобы получить логическую маску для столбцов, содержащих элемент "?":

(pd_df == "?").any(axis=0)

и получить маску для строк:

(pd_df == "?").any(axis=1)

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

(pd_df == "?").any().any()

Для сравнения, в polars лучшее, что я смог придумать, это следующее:

import polars as pl
pl_df = pl.DataFrame(data)

Чтобы получить маску для столбцов:

(pl_df == "?").select(pl.all().any())

Чтобы получить маску для строк:

pl_df.select(
        pl.concat_list(pl.all() == "?").alias("mask")
).select(
    pl.col("mask").arr.eval(pl.element().any()).arr.first()
)

И чтобы получить одно логическое значение:

pl_df.select(
        pl.concat_list(pl.all() == "?").alias("mask")
).select(
    pl.col("mask").arr.eval(pl.element().any()).arr.first()
)["mask"].any()

Последние два случая кажутся особенно многословными и запутанными для такой простой задачи, поэтому мне интересно, есть ли более короткие/быстрые эквиваленты?

Почему в 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 может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
3
0
127
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

  • все
>>> df.select(pl.all() == "?")
shape: (3, 2)
┌───────┬───────┐
│ A     ┆ B     │
│ ---   ┆ ---   │
│ bool  ┆ bool  │
╞═══════╪═══════╡
│ false ┆ false │
│ false ┆ true  │
│ true  ┆ false │
└───────┴───────┘
  • колонка
>>> df.select((pl.all() == "?").any())
shape: (1, 2)
┌──────┬──────┐
│ A    ┆ B    │
│ ---  ┆ ---  │
│ bool ┆ bool │
╞══════╪══════╡
│ true ┆ true │
└──────┴──────┘
  • ряд
>>> df.select(pl.any(pl.all() == "?"))
shape: (3, 1)
┌───────┐
│ any   │
│ ---   │
│ bool  │
╞═══════╡
│ false │
│ true  │
│ true  │
└───────┘
  • одинокий
>>> df.select(pl.any(pl.all() == "?").any())
shape: (1, 1)
┌──────┐
│ any  │
│ ---  │
│ bool │
╞══════╡
│ true │
└──────┘

Мы должны добавить это в документацию.

Igor Marcos Riegel 24.04.2023 16:17
Ответ принят как подходящий

Я думаю, что одна вещь, которая может сделать это более запутанным, заключается в том, что вы не делаете все в контексте выбора. Другими словами, не делайте этого: (pl_df == "?")

Первое, что мы можем сделать, это

pl_df.select(pl.all()= = "?")
shape: (3, 2)
┌───────┬───────┐
│ A     ┆ B     │
│ ---   ┆ ---   │
│ bool  ┆ bool  │
╞═══════╪═══════╡
│ false ┆ false │
│ false ┆ true  │
│ true  ┆ false │
└───────┴───────┘

Когда мы называем pl.all(), это означает все столбцы. Для каждого столбца мы преобразовываем его исходное значение в логическое значение того, равно ли оно ?

Теперь давайте сделаем это:

pl_df.select((pl.all()= = "?").any())

shape: (1, 2)
┌──────┬──────┐
│ A    ┆ B    │
│ ---  ┆ ---  │
│ bool ┆ bool │
╞══════╪══════╡
│ true ┆ true │
└──────┴──────┘

Это дает вам значение для каждого столбца. Все, что мы сделали, это добавили .any, что говорит о том, что если что-то в скобках, предшествующих этому, истинно, то вернуть True.

Теперь давайте сделаем

pl_df.select(pl.any(pl.all()= = "?"))

shape: (3, 1)
┌───────┐
│ any   │
│ ---   │
│ bool  │
╞═══════╡
│ false │
│ true  │
│ true  │
└───────┘

Когда мы вызываем pl.any(...), он будет делать это построчно для любого ....

В конце концов, если мы сложим их вместе...

pl_df.select((pl.any(pl.all()= = "?")).any())

shape: (1, 1)
┌──────┐
│ any  │
│ ---  │
│ bool │
╞══════╡
│ true │
└──────┘

затем мы получаем единственное значение, указывающее, что где-то в фрейме данных есть элемент, равный "?"

Мы должны добавить это в документацию.

Igor Marcos Riegel 24.04.2023 16:17

Большое спасибо! Думаю, меня сбил с толку раздел руководства пользователя о построчных вычислениях (pola-rs.github.io/polars-book/user-guide/dsl/list_context.h‌​tml). Так что я тоже согласен с Игорем :)

Qunatized 25.04.2023 18:15

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