Фильтр фрейма данных pandas — Верхняя и нижняя N строк

#python #pandas

#питон #панды

Вопрос:

У меня есть фрейм данных pandas с датами и значениями.

 import pandas as pd df = pd.DataFrame({'date':['11-10','11-10','11-10','12-10','12-10','12-10'],  'id': [1, 1, 2, 1, 1, 2],  'val':[20, 30, 40, 50, 25, 35] })  

Я бы хотел, чтобы фильтр фрейма данных включал только верхние и нижние N строк для каждой даты. Допустим, N = 2. Тогда фрейм данных отбросит 1-ю строку 11-10 20 и 5-ю строку 12-10 25 .

Надеясь на решение, которое может масштабироваться для разных значений N .

Ответ №1:

Вы можете сгруппировать date фрейм данных, затем вызвать nlargest val столбец, передав значение N :

 gt;gt;gt; df.groupby('date')['val'].nlargest(2) date  11-10 2 40  1 30 12-10 3 50  5 35 Name: val, dtype: int64  

При необходимости вы можете вызвать to_frame() результирующую серию, чтобы преобразовать ее в фрейм данных.

Для обновленного вопроса вы все еще можете реализовать приведенный выше код с некоторыми дополнительными работами, чтобы также получить идентификаторы, а затем выполнить внутреннее слияние с исходным фреймом данных:

 out= (df.set_index('id')  .groupby(['date'])['val']  .nlargest(2)  .to_frame('val')  .reset_index()  .merge(df, how='inner')  )  

выход:

 date id val 0 11-10 2 40 1 11-10 1 30 2 12-10 1 50 3 12-10 2 35  

Комментарии:

1. Однако я хотел бы сохранить столбцы в groupby. Когда я запускаю это, я получаю только серию.

2. Вот почему я упомянул, что вы можете дополнительно позвонить to_frame , чтобы преобразовать его в фрейм данных, и даже передать имя столбца: df.groupby('date')['val'].nlargest(2).to_frame('val')

3. Я получаю фрейм данных только с одним столбцом, val . Столбцы, используемые в groupby, будут потеряны. Я бы хотел их сохранить.

4. Вы имеете в виду, что у вас тоже есть дополнительные колонки?

5. Да, у меня есть две колонки groupby . Извините, это макет df, размещенный на SO.

Ответ №2:

Вы можете сделать:

 index_of_N_greatest_vals = df.groupby('date')['val'].nlargest(N).reset_index()['level_1'] df1 = df[df.index.isin(index_of_N_greatest_vals)]  

Выход:

 date id val 1 11-10 1 30 2 11-10 2 40 3 12-10 1 50 5 12-10 2 35  

Ответ №3:

Один из вариантов состоит в том, чтобы отсортировать столбцы и взять хвост группы.:

 (df.sort_values(['date', 'val'])  .groupby('date', sort = False)  .tail(n=2) )  date id val 1 11-10 1 30 2 11-10 2 40 5 12-10 2 35 3 12-10 1 50