Я пытаюсь отфильтровать фрейм данных, чтобы найти первое появление максимального значения в столбце категории. В моих данных нет гарантии, что существует одно уникальное максимальное значение, может быть несколько значений, но мне нужно только первое появление.
Тем не менее, я не могу найти способ ограничить максимальную часть фильтра, в настоящее время я добавляю дополнительный фильтр в другой столбец, обычно основанный на времени, и беру минимальное значение.
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 │
└─────┴─────────┴───────────┘
Однако я бы предпочел упростить вышеизложенное, чтобы требовалось передавать только ссылки на столбцы «Максимум» и «Категория».
Я упускаю здесь что-то очевидное?
Обновлено: добавлен пример фрейма данных и вывода.
Реальные значения данных записываются во время тестирования характеристик материала, поэтому не гарантируется, что все будет в порядке, но мне нужно максимальное значение для каждой категории, чтобы затем определить другие параметры с максимальным значением. Надеюсь, это имеет смысл. И спасибо за ваш пост. Я сейчас не у компьютера, чтобы проверить, но сделаю это ради ваших ответов и ответов Романа Пекарса.






Я бы предложил следующий подход:
cat столбцу первымmax_colТут может быть 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 │
└─────┴─────────┴───────────┘
Это работало нормально, но оба метода не всегда выбирали первое вхождение максимального значения. Но отсутствие примера меня очень впечатлило: он так близко подошел к решению.
Да, если вам нужен «первый», то решение @jcurious подойдет вам. Если вам нужно выбрать тот, который основан на других столбцах, решение должно работать.
Возможно, это потребуется в будущих инструментах, поэтому они определенно пригодятся 😊
Я также обновил решение для «первого» появления максимального значения.
Похоже, вы запрашиваете .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 неясно, какой индекс он возвращает, хотя их несколько. Может быть первым, но может быть и любым другим, в том числе последним или произвольным.
@levantpied Я думаю, что документы просто нуждаются в разъяснениях. Я считаю, что он гарантированно будет первым - аналогично тому, как это работает в пандах: «Если максимум достигнут в нескольких местах, возвращается позиция первой строки».
Означает ли это, что
other_colгарантированно будет отсортирован? (и в этом случае используется только для обеспечения «первого» поведения?)