Sur un problème concret, disons que j'ai un 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
Je veux trouver, pour chaque "mot", le "tag" qui a le plus "compte". Donc, le retour serait quelque chose comme
Word tag count
1 the S 20
2 a T 60
3 an T 5
Je ne me soucie pas de la colonne de compte ou si la commande/Index est original ou foiré. Retourner un dictionnaire {'the': 'S', ...} est parfait.
J'espère que je peux faire
DF.groupby(['Word']).agg(lambda x: x['tag'][ x['count'].argmax() ] )
mais ça ne marche pas. Je ne peux pas accéder aux informations de la colonne.
Plus abstraitement, que fait la fonction dans agg () ) voir comme son argument?
au fait, est-ce que .agg () est identique à .aggregate ()?
Merci beaucoup.
agg
est identique à aggregate
. Son appelable est passé les colonnes (Series
objets) du DataFrame
, un à la fois.
Vous pouvez utiliser idxmax
pour collecter les étiquettes d'index des lignes avec le nombre maximal:
idx = df.groupby('Word')['count'].idxmax()
print(idx)
les rendements
Word
a 2
an 3
the 1
Name: count
puis utilisez loc
pour sélectionner ces lignes dans les colonnes Word
et tag
:
print(df.loc[idx, ['Word', 'tag']])
les rendements
Word tag
2 a T
3 an T
1 the S
Notez que idxmax
renvoie l'index labels. df.loc
peut être utilisé pour sélectionner des lignes par étiquette. Mais si l’index n’est pas unique, c’est-à-dire s’il existe des lignes avec des étiquettes d’index dupliquées, alors df.loc
sélectionnera toutes les lignes avec les étiquettes listées dans idx
. Alors faites attention que df.index.is_unique
est True
si vous utilisez idxmax
avec df.loc
Alternative, vous pouvez utiliser apply
. L'appelable de apply
reçoit un sous-DataFrame qui vous donne accès à toutes les colonnes:
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()]))
les rendements
Word
a T
an T
the S
L'utilisation de idxmax
et loc
est généralement plus rapide que apply
, en particulier pour les grands DataFrames. Utilisation de% timeit d'IPython:
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
Si vous voulez un dictionnaire mappant des mots en balises, vous pouvez utiliser set_index
et to_dict
comme ça:
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'}
Voici un moyen simple de déterminer ce qui est en train d'être adopté (la solution unutbu), puis d'appliquer la solution!
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
votre fonction ne fait qu'opérer (dans ce cas) sur une sous-section du cadre avec la variable groupée ayant tous la même valeur (dans ce cas, 'Word'), si vous passez une fonction, vous devez alors gérer l'agrégation des colonnes potentiellement non chaîne; les fonctions standard, comme 'sum' le font pour vous
Automatiquement ne pas agréger sur les colonnes de chaîne
In [41]: df.groupby('Word').sum()
Out[41]:
count
Word
a 90
an 5
the 30
Vous agrégez sur toutes les colonnes
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
Vous pouvez faire à peu près n'importe quoi dans la fonction
In [43]: df.groupby('Word').apply(lambda x: x['count'].sum())
Out[43]:
Word
a 90
an 5
the 30