El marco de datos de pandas obtiene la primera fila de cada grupo

137

Tengo unos pandas DataFramecomo los siguientes.

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"]})

Quiero agrupar esto por ["id", "valor"] y obtener la primera fila de cada grupo.

        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

Gastos esperados

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

Intenté seguir lo que solo da la primera fila de DataFrame. Cualquier ayuda con respecto a esto es apreciada.

In [25]: for index, row in df.iterrows():
   ....:     df2 = pd.DataFrame(df.groupby(['id','value']).reset_index().ix[0])
Nilani Algiriyage
fuente
2
Me doy cuenta de que esta pregunta es bastante antigua, pero sugeriría aceptar la respuesta de @vital_dml porque el comportamiento first()con respecto a nans es muy sorprendente y es algo que creo que la mayoría de la gente no esperará.
user545424

Respuestas:

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

Si necesitas idcomo columna:

>>> 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

Para obtener n primeros registros, puede usar 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
fuente
1
¡Muchas gracias! Funcionó bien :) No es posible obtener la segunda fila de la misma manera, ¿verdad? ¿Puedes explicarlo también?
Nilani Algiriyage
g = df.groupby (['session']) g.agg (lambda x: x.iloc [0]) esto también está funcionando, ¿no tienes idea de obtener el segundo valor? :(
Nilani Algiriyage
supongamos que contando desde arriba desea obtener el número de fila top_n, luego dx = df.groupby ('id'). head (top_n) .reset_index (drop = True) y suponga que contando desde abajo desea obtener el número de fila bottom_n, luego dx = df.groupby ('id'). tail (bottom_n) .reset_index (drop = True)
Quetzalcoatl
3
En caso de que desee las últimas n filas, use tail(n)(el valor predeterminado es n = 5) ( ref. ). No debe confundirse con last(), cometí ese error.
rocarvaj
groupby('id',as_index=False)también se mantiene idcomo una columna
Richard DiSalvo
50

Esto le dará la segunda fila de cada grupo (cero indexado, nth (0) es lo mismo que first ()):

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

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

wij
fuente
8
Si desea múltiplos, como los tres primeros, por ejemplo, use una secuencia como nth((0,1,2))o nth(range(3)).
Ronan Paixão
@ RonanPaixão: De alguna manera, cuando doy alcance, arroja un error:TypeError: n needs to be an int or a list/set/tuple of ints
Pacífica
@Peaceful: ¿estás usando Python 3? Si es así, range(3)no devuelve una lista a menos que escriba list(range(3)).
Ben
41

Sugeriría usar en .nth(0)lugar de .first()si necesita obtener la primera fila.

La diferencia entre ellos es cómo manejan los NaN, por .nth(0)lo que devolverá la primera fila del grupo sin importar cuáles sean los valores en esta fila, mientras .first()que eventualmente devolverá el primer valor no NaN en cada columna.

Por ejemplo, si su conjunto de datos es:

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

Y

>>> df.groupby('id').first()
    value
id        
1    first
2    second
3    first
4    first
vital_dml
fuente
1
buen punto. .head(1)también parece comportarse como .nth(0), excepto por el índice
Richard DiSalvo
1
Otra diferencia es que nth (0) preservará el índice original (si as_index = False), mientras que first () no lo hará. Una vez para mí, esta fue una diferencia sustancial, ya que necesitaba el índice en sí.
Oleg O
7

tal vez esto es lo que quieres

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.
fuente
7

Si solo necesita la primera fila de cada grupo con el que podemos hacerlo drop_duplicates, observe el método predeterminado de la función 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
fuente