Как фильтровать фрейм данных поляров по первому максимальному значению при использовании over?

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

Тем не менее, я не могу найти способ ограничить максимальную часть фильтра, в настоящее время я добавляю дополнительный фильтр в другой столбец, обычно основанный на времени, и беру минимальное значение.

df = pl.DataFrame(
    {
        "cat": [1, 1, 1, 2, 2, 2, 2, 3, 3, 3],
        "max_col": [12, 24, 36, 15, 50, 50, 45, 20, 40, 60],
        "other_col": [25, 50, 75, 125, 150, 175, 200, 225, 250, 275],
    }
)

df = df.filter(pl.col("max_col") == pl.col("max_col").max().over("cat")).filter(
    pl.col("other_col") == pl.col("other_col").min().over("cat")
)

shape: (3, 3)
┌─────┬─────────┬───────────┐
│ cat ┆ max_col ┆ other_col │
│ --- ┆ ---     ┆ ---       │
│ i64 ┆ i64     ┆ i64       │
╞═════╪═════════╪═══════════╡
│ 1   ┆ 36      ┆ 75        │
│ 2   ┆ 50      ┆ 150       │
│ 3   ┆ 60      ┆ 275       │
└─────┴─────────┴───────────┘

Однако я бы предпочел упростить вышеизложенное, чтобы требовалось передавать только ссылки на столбцы «Максимум» и «Категория».

Я упускаю здесь что-то очевидное?

Обновлено: добавлен пример фрейма данных и вывода.

Означает ли это, что other_col гарантированно будет отсортирован? (и в этом случае используется только для обеспечения «первого» поведения?)

jqurious 01.06.2024 12:19

Реальные значения данных записываются во время тестирования характеристик материала, поэтому не гарантируется, что все будет в порядке, но мне нужно максимальное значение для каждой категории, чтобы затем определить другие параметры с максимальным значением. Надеюсь, это имеет смысл. И спасибо за ваш пост. Я сейчас не у компьютера, чтобы проверить, но сделаю это ради ваших ответов и ответов Романа Пекарса.

niko86 01.06.2024 14:09
Почему в 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
2
171
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Я бы предложил следующий подход:

Тут может быть 2 варианта:

Если вы хотите первое появление max(max_col)

В этом случае вы хотите использовать maintain_order = True во время сортировки:

(
    df
    .group_by('cat', maintain_order=True)
    .agg(
        pl.all()
        .sort_by('max_col', descending=True, maintain_order=True).first()
    )
)

или, используя DataFrame.sort() и group_by.first():

(
    df
    .sort('max_col', descending=True, maintain_order=True)
    .group_by('cat', maintain_order=True)
    .first()
)

┌─────┬─────────┬───────────┐
│ cat ┆ max_col ┆ other_col │
│ --- ┆ ---     ┆ ---       │
│ i64 ┆ i64     ┆ i64       │
╞═════╪═════════╪═══════════╡
│ 1   ┆ 36      ┆ 75        │
│ 2   ┆ 50      ┆ 150       │
│ 3   ┆ 60      ┆ 275       │
└─────┴─────────┴───────────┘

Если вам нужно положиться на порядок other_col

В этом случае вы можете дополнительно отсортировать по other_col:

(
    df
    .group_by('cat', maintain_order=True)
    .agg(
        pl.all()
        .sort_by('max_col','other_col', descending=[True, False]).first()
    )
)

# or

(
    df
    .sort('max_col','other_col', descending=[True, False])
    .group_by('cat', maintain_order=True)
    .first()
)

┌─────┬─────────┬───────────┐
│ cat ┆ max_col ┆ other_col │
│ --- ┆ ---     ┆ ---       │
│ i64 ┆ i64     ┆ i64       │
╞═════╪═════════╪═══════════╡
│ 3   ┆ 60      ┆ 275       │
│ 2   ┆ 50      ┆ 150       │
│ 1   ┆ 36      ┆ 75        │
└─────┴─────────┴───────────┘

Это работало нормально, но оба метода не всегда выбирали первое вхождение максимального значения. Но отсутствие примера меня очень впечатлило: он так близко подошел к решению.

niko86 01.06.2024 17:05

Да, если вам нужен «первый», то решение @jcurious подойдет вам. Если вам нужно выбрать тот, который основан на других столбцах, решение должно работать.

Roman Pekar 01.06.2024 17:18

Возможно, это потребуется в будущих инструментах, поэтому они определенно пригодятся 😊

niko86 01.06.2024 23:58

Я также обновил решение для «первого» появления максимального значения.

Roman Pekar 04.06.2024 09:17
Ответ принят как подходящий

Похоже, вы запрашиваете .arg_max() (и значение other_col на самом деле не имеет значения)

df.filter(
   (pl.int_range(pl.len()) == pl.col.max_col.arg_max()).over("cat")
)
shape: (3, 3)
┌─────┬─────────┬───────────┐
│ cat ┆ max_col ┆ other_col │
│ --- ┆ ---     ┆ ---       │
│ i64 ┆ i64     ┆ i64       │
╞═════╪═════════╪═══════════╡
│ 1   ┆ 36      ┆ 75        │
│ 2   ┆ 50      ┆ 150       │
│ 3   ┆ 60      ┆ 275       │
└─────┴─────────┴───────────┘

Объяснение

.int_range() дает нам номер строки для каждой группы, и вам нужен тот, который соответствует .arg_max()

df.with_columns(
   row_number = pl.int_range(pl.len()).over("cat"),
   row_i_want = pl.col.max_col.arg_max().over("cat")
)
shape: (10, 5)
┌─────┬─────────┬───────────┬────────────┬────────────┐
│ cat ┆ max_col ┆ other_col ┆ row_number ┆ row_i_want │
│ --- ┆ ---     ┆ ---       ┆ ---        ┆ ---        │
│ i64 ┆ i64     ┆ i64       ┆ i64        ┆ u32        │
╞═════╪═════════╪═══════════╪════════════╪════════════╡
│ 1   ┆ 12      ┆ 25        ┆ 0          ┆ 2          │
│ 1   ┆ 24      ┆ 50        ┆ 1          ┆ 2          │
│ 1   ┆ 36      ┆ 75        ┆ 2          ┆ 2          │ # KEEP
│ 2   ┆ 15      ┆ 125       ┆ 0          ┆ 1          │
│ 2   ┆ 50      ┆ 150       ┆ 1          ┆ 1          │ # KEEP
│ 2   ┆ 50      ┆ 175       ┆ 2          ┆ 1          │
│ 2   ┆ 45      ┆ 200       ┆ 3          ┆ 1          │
│ 3   ┆ 20      ┆ 225       ┆ 0          ┆ 2          │
│ 3   ┆ 40      ┆ 250       ┆ 1          ┆ 2          │
│ 3   ┆ 60      ┆ 275       ┆ 2          ┆ 2          │ # KEEP
└─────┴─────────┴───────────┴────────────┴────────────┘

Из документов arg_max неясно, какой индекс он возвращает, хотя их несколько. Может быть первым, но может быть и любым другим, в том числе последним или произвольным.

levant pied 03.06.2024 19:25

@levantpied Я думаю, что документы просто нуждаются в разъяснениях. Я считаю, что он гарантированно будет первым - аналогично тому, как это работает в пандах: «Если максимум достигнут в нескольких местах, возвращается позиция первой строки».

jqurious 05.06.2024 09:17

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