Группировка по фрейму данных Pandas с настраиваемой функцией агрегирования - PullRequest
0 голосов
/ 23 февраля 2019

Предположим, у нас есть фрейм данных:

df = pd.DataFrame({'Animal' : ['Falcon', 'Falcon','Parrot', 'Parrot'],
                   'Max Speed' : [380.1, 370.3, 24.77, -12.55]})    

Я должен построить функцию, аналогичную минимуму по абсолютной величине, он должен вернуть элемент ближе к нулю.Группируя по 'Animal', в нашем случае она должна вернуть:

   Animal  Max Speed
0  Falcon     370.30
1  Parrot     -12.55

Я попробовал такую ​​функцию:

def nearzero():
   absolute = [abs(number) for number in data]
   i = absolute.index(min(absolute))
   return data[i]

Она должна вернуть элемент, найденный в индексе, гдеабсолютное значение минимально.Но это не работает:

df.groupby(['Animal']).agg({'Max Speed': [nearzero]})

Плохо определены функция или группа?

Ответы [ 3 ]

0 голосов
/ 23 февраля 2019

Вы можете определить функцию в Python,

def abs_min(x):
    for elem in x:
        if abs(elem) == min(abs(x)):
            return elem

df.groupby('Animal')['Max Speed'].apply(abs_min)

Animal
Falcon    370.30
Parrot    -12.55

Или использовать генератор,

df.groupby('Animal')['Max Speed'].apply(lambda x: next(i for i in x if abs(i) == min(abs(x))))
0 голосов
/ 23 февраля 2019

Определите вашу функцию как:

def nearzero(data):
    dat = data.tolist()
    absolute = [abs(number) for number in dat]
    return dat[absolute.index(min(absolute))]

Обратите внимание, что эта функция вызывается с df column ( Series ) в качестве аргумента, но выбор должен бытьвыполняется из базового списка .

Затем вызывается:

df.groupby(['Animal'])['Max Speed'].apply(nearzero)

Второй вариант , без явного преобразования в базовый список:

Определите функцию как:

def nearzero2(data):
    return data[data.abs().idxmin()]

Затем вызовите:

df.groupby(['Animal'])['Max Speed'].apply(nearzero2)

Или получите результат, как в вашем квестрионе:

df.groupby(['Animal']).agg({'Max Speed': nearzero2}).reset_index()
0 голосов
/ 23 февраля 2019

Я думаю, вам нужно DataFrameGroupBy.idxmin для индексов по минутам для групп, также конвертировать столбец Max Speed в abs, последний вызов loc для выбранных строк:

df = df.loc[df['Max Speed'].abs().groupby(df['Animal']).idxmin()]
print (df)
   Animal  Max Speed
1  Falcon     370.30
3  Parrot     -12.55

Другое решение с новым столбцом:

df['Max Speed Abs'] = df['Max Speed'].abs()
df = df.loc[df.groupby('Animal')['Max Speed Abs'].idxmin()]

РЕДАКТИРОВАТЬ: Для groupby с кратным Series использовать:

df = pd.DataFrame({'Animal' : ['Falcon', 'Falcon','Parrot', 'Parrot'],
                   'Max Speed' : [380.1, 370.3, 24.77, -12.55],
                   'Dates':['2010-10-09'] * 4})  

df = df.loc[df['Max Speed'].abs().groupby([df['Animal'], df['Dates']]).idxmin()]
print (df)
   Animal  Max Speed       Dates
1  Falcon     370.30  2010-10-09
3  Parrot     -12.55  2010-10-09
...