Подтвердить что ты не робот

Сохраняйте другие столбцы при групповом

Я использую groupby на фрейме данных pandas для удаления всех строк, у которых нет минимума определенного столбца. Примерно так:

df1 = df.groupby("item", as_index=False)["diff"].min()

Однако, если у меня больше этих двух столбцов, другие столбцы (например, otherstuff в моем примере) будут удалены. Могу ли я сохранить эти столбцы, используя groupby, или мне придется искать другой способ отбрасывания строк?

Мои данные выглядят так:

    item    diff   otherstuff
   0   1       2            1
   1   1       1            2
   2   1       3            7
   3   2      -1            0
   4   2       1            3
   5   2       4            9
   6   2      -6            2
   7   3       0            0
   8   3       2            9

и должно закончиться как:

    item   diff  otherstuff
   0   1      1           2
   1   2     -6           2
   2   3      0           0

но я получаю это:

    item   diff
   0   1      1           
   1   2     -6           
   2   3      0                 

Я просматривал документацию и ничего не могу найти. Я пытался:

df1 = df.groupby(["item", "otherstuff"], as_index=false)["diff"].min()

df1 = df.groupby("item", as_index=false)["diff"].min()["otherstuff"]

df1 = df.groupby("item", as_index=false)["otherstuff", "diff"].min()

Но ни одна из этих работ (с последним я понял, что синтаксис предназначен для агрегирования после создания группы).

4b9b3361

Ответ 1

Метод # 1: используйте idxmin() чтобы получить индексы элементов минимальной diff, а затем выберите те:

>>> df.loc[df.groupby("item")["diff"].idxmin()]
   item  diff  otherstuff
1     1     1           2
6     2    -6           2
7     3     0           0

[3 rows x 3 columns]

Способ № 2: сортировка по diff, а затем взять первый элемент в каждой группе item:

>>> df.sort_values("diff").groupby("item", as_index=False).first()
   item  diff  otherstuff
0     1     1           2
1     2    -6           2
2     3     0           0

[3 rows x 3 columns]

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

Ответ 2

Вы можете использовать DataFrame.sort_values с DataFrame.drop_duplicates:

df = df.sort_values(by='diff').drop_duplicates(subset='item')
print (df)
   item  diff  otherstuff
6     2    -6           2
7     3     0           0
1     1     1           2

Если возможно, несколько минимальных значений для групп и для всех минимальных строк используйте boolean indexing с transform для минимальных значений для групп:

print (df)
   item  diff  otherstuff
0     1     2           1
1     1     1           2 <-multiple min
2     1     1           7 <-multiple min
3     2    -1           0
4     2     1           3
5     2     4           9
6     2    -6           2
7     3     0           0
8     3     2           9

print (df.groupby("item")["diff"].transform('min'))
0    1
1    1
2    1
3   -6
4   -6
5   -6
6   -6
7    0
8    0
Name: diff, dtype: int64

df = df[df.groupby("item")["diff"].transform('min') == df['diff']]
print (df)
   item  diff  otherstuff
1     1     1           2
2     1     1           7
6     2    -6           2
7     3     0           0

Ответ 3

Вышеприведенный ответ отлично подойдет, если вам понадобится 1 мин. В моем случае может быть несколько минут, и мне нужны все строки, равные min, которые .idxmin() не дает вам. Это сработало

def filter_group(dfg, col):
    return dfg[dfg[col] == dfg[col].min()]

df = pd.DataFrame({'g': ['a'] * 6 + ['b'] * 6, 'v1': (list(range(3)) + list(range(3))) * 2, 'v2': range(12)})
df.groupby('g',group_keys=False).apply(lambda x: filter_group(x,'v1'))

В стороне, .filter() также имеет отношение к этому вопросу, но не работает для меня.

Ответ 4

Если вы знаете, что все ваши "предметы" имеют более одной записи, которую вы можете отсортировать, используйте duplicated:

df.sort_values(by='diff').duplicated(subset='item', keep='first')