Группировка фильтра кадров данных на основе подмножества

df_example = pd.DataFrame({'name': ['a', 'a', 'a', 'b', 'b', 'b'],
                          'class': [1, 2, 2, 3, 2, 2],
                          'price': [3, 4, 2, 1, 6, 5]})

Я хочу отфильтровать каждый name, где price больше наименьшего price в подмножестве class==2 внутри name группы:

df_example.sort_values(['name', 'price'], inplace=True)
df_tem = df_example[df_example['class'] == 2].groupby('name').first()

Ниже приведен псевдокод:

df_example.groupby('name').apply(lambda key, val: val['price'] > df_tem.loc[key]['price']).reset_index()

Есть ли какой-нибудь эффективный способ добиться чего-то вроде фильтра фрейма данных на основе подмножества внутри groupby

результат:

наименьшая цена с class=2 для каждой группы имен df_tem:

    class   price
name        
a   2   2
b   2   5

Поэтому,

group a: price>2; group b: price>5

выход:

pd.DataFrame({'name': ['a', 'a', 'b'],
                          'class': [1, 2, 2],
                          'price': [3, 4, 6]})

Обновлять:

на самом деле у меня есть идея создать новый столбец с именем «самый маленький», а затем отфильтровать

df_example by df_example['price'] > df_example['smallest ']. 

Знаете ли вы, как быстро создать такой столбец, что-то вроде

df_example['smallest '] = df_example[df_example['class'] == 2].groupby('name')['price'].transform('first')

вышеописанный способ еще есть nan

@Ben.T, пожалуйста, посмотрите обновление, ожидаемый отфильтрованный фрейм данных

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

Ответы 3

Вы можете сделать это, используя groupby.transform, чтобы выровнять значение min для каждого имени where class==2 и сравнить gt (больше чем) с ценой строки

df_output = (
    df_example
    .loc[lambda x: 
         x['price'].gt(x['price'].where(x['class'].eq(2))
                       .groupby(x['name']).transform(min))]
)
print(df_output)
#   name  class  price
# 0    a      1      3
# 1    a      2      4
# 4    b      2      6

на самом деле у меня есть идея создать новый столбец с именем smallest, а затем отфильтровать df_example по df_example['price'] > df_example['smallest ']. Знаете ли вы, как быстро создать такой столбец, например df_example['smallest '] = df_example[df_example['class'] == 2].groupby('name')['price'].transform('first'), приведенный выше способ все еще имеет значение nan

user6703592 21.07.2024 16:43

@user6703592 user6703592 да, можете df_example['smallest'] = df_example['price'].where(df_example['class'].eq(2)).groupby‌​(df_example['name'])‌​.transform(min) но я не вижу смысла создавать столбец, если вы не используете это значение, кроме как для фильтрации

Ben.T 21.07.2024 17:02

Вы можете получить min цену для класса 2, merge вставить ее df_example в новый столбец min_price, а затем использовать ее для фильтрации:

m = (
    df_example[df_example["class"] == 2]
    .groupby("name")["price"]
    .min()
    .reset_index(name = "min_price")
)

df_example = (
    df_example.merge(m, how = "left", on = "name")
    .query("price > min_price")
    .drop(columns = "min_price")
)
  name  class  price
0    a      1      3
1    a      2      4
4    b      2      6

извините, неправильно отредактировал свой ответ

user6703592 21.07.2024 16:48
Ответ принят как подходящий

Код

Используйте groupby, чтобы агрегировать минимум, и используйте map, чтобы сопоставить результат с name column для логического индексирования.

m = df_example[df_example['class'] == 2].groupby('name')['price'].min()
out = df_example[df_example['price'] > df_example['name'].map(m)]

вне

  name  class  price
0    a      1      3
1    a      2      4
4    b      2      6

обновить дополнительный вопрос

Кроме того, если вы хотите указать имя, для которого class=2 не существует, используйте код ниже.

m = df_example[df_example['class'] == 2].groupby('name')['price'].min()
cond1 = df_example['price'] > df_example['name'].map(m)
cond2 = ~df_example['name'].isin(m.index)
out = df_example[cond1 | cond2]

новый пример

df_example = pd.DataFrame({'name': ['a', 'a', 'a', 'b', 'b', 'b', 'c'],
                          'class': [1, 2, 2, 3, 2, 2, 3],
                          'price': [3, 4, 2, 1, 6, 5, 5]})

вне:

  name  class  price
0    a      1      3
1    a      2      4
4    b      2      6
6    c      3      5

очень хороший ответ, но я могу забыть случай, когда имени нет на карте, скажем name = 'c', class=3, price=5, я все равно хочу сохранить эти строки.

user6703592 21.07.2024 17:05

@user6703592 user6703592 я обновляю свой ответ

Panda Kim 21.07.2024 17:10

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