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

Python pandas, DF.groupby(). agg(), ссылка столбца в agg()

По конкретной задаче, скажем, у меня есть DataFrame DF

     word  tag count
0    a     S    30
1    the   S    20
2    a     T    60
3    an    T    5
4    the   T    10 

Я хочу найти для каждого "слова", "тега", который имеет наибольшее количество "счет" . Таким образом, возвращение будет чем-то вроде

     word  tag count
1    the   S    20
2    a     T    60
3    an    T    5

Мне не нужен столбец count или если порядок/индекс оригинален или испорчен. Возвращение словаря { '': 'S',...} отлично.

Я надеюсь, что смогу сделать

DF.groupby(['word']).agg(lambda x: x['tag'][ x['count'].argmax() ] )

но это не сработает. Я не могу получить доступ к информации о столбцах.

Более абстрактно что функция в agg (function) видит в качестве аргумента?

btw, является .agg() тем же, что и .aggregate()?

Большое спасибо.

4b9b3361

Ответ 1

agg совпадает с aggregate. Он вызываемый пропускает столбцы (Series objects) DataFrame, по одному за раз.


Вы можете использовать idxmax для сбора индексных меток строк с максимальным значением количество:

idx = df.groupby('word')['count'].idxmax()
print(idx)

дает

word
a       2
an      3
the     1
Name: count

а затем используйте loc, чтобы выбрать те строки в столбцах word и tag:

print(df.loc[idx, ['word', 'tag']])

дает

  word tag
2    a   T
3   an   T
1  the   S

Обратите внимание, что idxmax возвращает метки индекса. df.loc может использоваться для выбора строк по этикетке. Но если индекс не уникален, то есть, если есть строки с повторяющимися индексными метками, то df.loc выберет все строки с метками, указанными в idx. Поэтому будьте осторожны, если df.index.is_unique True, если вы используете idxmax с df.loc


Альтернативно, вы можете использовать apply. apply callable передается суб-DataFrame, который дает вам доступ ко всем столбцам:

import pandas as pd
df = pd.DataFrame({'word':'a the a an the'.split(),
                   'tag': list('SSTTT'),
                   'count': [30, 20, 60, 5, 10]})

print(df.groupby('word').apply(lambda subf: subf['tag'][subf['count'].idxmax()]))

дает

word
a       T
an      T
the     S

Использование idxmax и loc обычно быстрее, чем apply, особенно для больших DataFrames. Использование IPython% timeit:

N = 10000
df = pd.DataFrame({'word':'a the a an the'.split()*N,
                   'tag': list('SSTTT')*N,
                   'count': [30, 20, 60, 5, 10]*N})
def using_apply(df):
    return (df.groupby('word').apply(lambda subf: subf['tag'][subf['count'].idxmax()]))

def using_idxmax_loc(df):
    idx = df.groupby('word')['count'].idxmax()
    return df.loc[idx, ['word', 'tag']]

In [22]: %timeit using_apply(df)
100 loops, best of 3: 7.68 ms per loop

In [23]: %timeit using_idxmax_loc(df)
100 loops, best of 3: 5.43 ms per loop

Если вам нужен словарь, сопоставляющий слова с тегами, вы можете использовать set_index и to_dict следующим образом:

In [36]: df2 = df.loc[idx, ['word', 'tag']].set_index('word')

In [37]: df2
Out[37]: 
     tag
word    
a      T
an     T
the    S

In [38]: df2.to_dict()['tag']
Out[38]: {'a': 'T', 'an': 'T', 'the': 'S'}

Ответ 2

Вот простой способ выяснить, что проходит (решение unutbu), тогда "применяется"!

In [33]: def f(x):
....:     print type(x)
....:     print x
....:     

In [34]: df.groupby('word').apply(f)
<class 'pandas.core.frame.DataFrame'>
  word tag  count
0    a   S     30
2    a   T     60
<class 'pandas.core.frame.DataFrame'>
  word tag  count
0    a   S     30
2    a   T     60
<class 'pandas.core.frame.DataFrame'>
  word tag  count
3   an   T      5
<class 'pandas.core.frame.DataFrame'>
  word tag  count
1  the   S     20
4  the   T     10

ваша функция просто работает (в данном случае) в подразделе фрейма, где сгруппированная переменная имеет все одинаковое значение (в этом cas 'word'), если вы передаете функцию, тогда вам нужно иметь дело с агрегацией потенциально нестрочных столбцов; стандартные функции, такие как "sum" делают это для вас

Автоматически НЕ объединяется в столбцах строк

In [41]: df.groupby('word').sum()
Out[41]: 
      count
word       
a        90
an        5
the      30

Вы агрегируете все столбцы

In [42]: df.groupby('word').apply(lambda x: x.sum())
Out[42]: 
        word tag count
word                  
a         aa  ST    90
an        an   T     5
the   thethe  ST    30

Вы можете сделать почти что угодно в функции

In [43]: df.groupby('word').apply(lambda x: x['count'].sum())
Out[43]: 
word
a       90
an       5
the     30