La trame de données Pandas obtient la première ligne de chaque groupe

137

J'ai un pandas DataFramecomme le suivant.

df = pd.DataFrame({'id' : [1,1,1,2,2,3,3,3,3,4,4,5,6,6,6,7,7],
                'value'  : ["first","second","second","first",
                            "second","first","third","fourth",
                            "fifth","second","fifth","first",
                            "first","second","third","fourth","fifth"]})

Je veux regrouper cela par ["id", "value"] et obtenir la première ligne de chaque groupe.

        id   value
0        1   first
1        1  second
2        1  second
3        2   first
4        2  second
5        3   first
6        3   third
7        3  fourth
8        3   fifth
9        4  second
10       4   fifth
11       5   first
12       6   first
13       6  second
14       6   third
15       7  fourth
16       7   fifth

Résultat attendu

    id   value
     1   first
     2   first
     3   first
     4  second
     5  first
     6  first
     7  fourth

J'ai essayé de suivre ce qui ne donne que la première ligne du fichier DataFrame. Toute aide à ce sujet est appréciée.

In [25]: for index, row in df.iterrows():
   ....:     df2 = pd.DataFrame(df.groupby(['id','value']).reset_index().ix[0])
Nilani Algiriyage
la source
2
Je me rends compte que cette question est assez ancienne, mais je suggérerais d'accepter la réponse de @vital_dml car le comportement de first()par rapport à nans est très surprenant et je pense que la plupart des gens ne s'y attendront pas.
user545424

Réponses:

238
>>> df.groupby('id').first()
     value
id        
1    first
2    first
3    first
4   second
5    first
6    first
7   fourth

Si vous avez besoin idcomme colonne:

>>> df.groupby('id').first().reset_index()
   id   value
0   1   first
1   2   first
2   3   first
3   4  second
4   5   first
5   6   first
6   7  fourth

Pour obtenir n premiers enregistrements, vous pouvez utiliser head ():

>>> df.groupby('id').head(2).reset_index(drop=True)
    id   value
0    1   first
1    1  second
2    2   first
3    2  second
4    3   first
5    3   third
6    4  second
7    4   fifth
8    5   first
9    6   first
10   6  second
11   7  fourth
12   7   fifth
Roman Pekar
la source
1
Merci beaucoup! A bien fonctionné :) Il n'est pas possible d'obtenir la deuxième ligne de la même manière, non? Pouvez-vous expliquer cela aussi?
Nilani Algiriyage
g = df.groupby (['session']) g.agg (lambda x: x.iloc [0]) cela fonctionne aussi, aucune idée d'obtenir la deuxième valeur? :(
Nilani Algiriyage
supposons qu'en comptant à partir du haut vous voulez obtenir le numéro de ligne top_n, puis dx = df.groupby ('id'). head (top_n) .reset_index (drop = True) et supposons qu'en comptant à partir du bas vous voulez obtenir le numéro de ligne bottom_n, then dx = df.groupby ('id'). tail (bottom_n) .reset_index (drop = True)
Quetzalcoatl
3
Si vous voulez les n dernières lignes, utilisez tail(n)(la valeur par défaut est n = 5) ( réf. ). À ne pas confondre last(), j'ai commis cette erreur.
rocarvaj
groupby('id',as_index=False)garde aussi idcomme colonne
Richard DiSalvo
50

Cela vous donnera la deuxième ligne de chaque groupe (zéro indexé, nième (0) est le même que first ()):

df.groupby('id').nth(1) 

Documentation: http://pandas.pydata.org/pandas-docs/stable/groupby.html#taking-the-nth-row-of-each-group

wij
la source
8
Si vous voulez des multiples, comme les trois premiers, par exemple, utilisez une séquence comme nth((0,1,2))ou nth(range(3)).
Ronan Paixão
@ RonanPaixão: D'une manière ou d'une autre, quand je donne de la portée, cela lance une erreur:TypeError: n needs to be an int or a list/set/tuple of ints
Paisible
@Peaceful: utilisez-vous Python 3? Si tel est le cas, range(3)ne renvoie pas de liste sauf si vous tapez list(range(3)).
Ben
41

Je suggère d'utiliser .nth(0)plutôt que .first()si vous avez besoin d'obtenir la première ligne.

La différence entre eux est la façon dont ils gèrent les NaN, donc .nth(0)retournera la première ligne du groupe quelles que soient les valeurs de cette ligne, alors que .first()finira par retourner la première non NaN valeur dans chaque colonne .

Par exemple, si votre ensemble de données est:

df = pd.DataFrame({'id' : [1,1,1,2,2,3,3,3,3,4,4],
            'value'  : ["first","second","third", np.NaN,
                        "second","first","second","third",
                        "fourth","first","second"]})

>>> df.groupby('id').nth(0)
    value
id        
1    first
2    NaN
3    first
4    first

Et

>>> df.groupby('id').first()
    value
id        
1    first
2    second
3    first
4    first
vital_dml
la source
1
bon point. .head(1)semble également se comporter comme .nth(0), sauf pour l'index
Richard DiSalvo
1
Une autre différence est que nth (0) conservera l'index d'origine (si as_index = False), alors que first () ne le sera pas. Une fois pour moi, c'était une différence substantielle, car j'avais besoin de l'index lui-même.
Oleg O le
7

c'est peut-être ce que tu veux

import pandas as pd
idx = pd.MultiIndex.from_product([['state1','state2'],   ['county1','county2','county3','county4']])
df = pd.DataFrame({'pop': [12,15,65,42,78,67,55,31]}, index=idx)
                pop
state1 county1   12
       county2   15
       county3   65
       county4   42
state2 county1   78
       county2   67
       county3   55
       county4   31
df.groupby(level=0, group_keys=False).apply(lambda x: x.sort_values('pop', ascending=False)).groupby(level=0).head(3)

> Out[29]: 
                pop
state1 county3   65
       county4   42
       county2   15
state2 county1   78
       county2   67
       county3   55
Siraj S.
la source
7

Si vous n'avez besoin que de la première ligne de chaque groupe avec drop_duplicateslequel nous pouvons faire , notez la méthode par défaut de la fonction keep='first'.

df.drop_duplicates('id')
Out[1027]: 
    id   value
0    1   first
3    2   first
5    3   first
9    4  second
11   5   first
12   6   first
15   7  fourth
YOBEN_S
la source