Dataframe Pandy pobiera pierwszy wiersz każdej grupy

150

Mam pandy, które DataFramelubią podążać.

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

Chcę to pogrupować według [„id”, „value”] i uzyskać pierwszy wiersz każdej grupy.

        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

Spodziewany rezultat

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

Próbowałem podążać za tym, co daje tylko pierwszy wiersz DataFrame. Każda pomoc w tym zakresie jest mile widziana.

In [25]: for index, row in df.iterrows():
   ....:     df2 = pd.DataFrame(df.groupby(['id','value']).reset_index().ix[0])
Nilani Algiriyage
źródło
3
Zdaję sobie sprawę, że to pytanie jest dość stare, ale sugerowałbym przyjęcie odpowiedzi przez @vital_dml, ponieważ zachowanie w first()odniesieniu do nans jest bardzo zaskakujące i myślę, że większość ludzi się nie spodziewa.
user545424

Odpowiedzi:

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

Jeśli potrzebujesz idjako kolumna:

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

Aby uzyskać n pierwszych rekordów, możesz użyć funkcji 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
źródło
1
Wielkie dzięki! Zadziałało dobrze :) Nie można uzyskać drugiego rzędu w ten sam sposób, prawda? Czy możesz to po prostu wyjaśnić?
Nilani Algiriyage
g = df.groupby (['sesja']) g.agg (lambda x: x.iloc [0]) to też działa, nie masz pojęcia o uzyskaniu drugiej wartości? :(
Nilani Algiriyage
załóżmy, że licząc od góry chcesz uzyskać numer wiersza top_n, a następnie dx = df.groupby ('id'). head (top_n) .reset_index (drop = True) i przypuśćmy, że licząc od dołu chcesz uzyskać numer wiersza bottom_n, then dx = df.groupby ('id'). tail (bottom_n) .reset_index (drop = True)
Quetzalcoatl
4
Jeśli chcesz mieć ostatnie n wierszy, użyj tail(n)(domyślnie n = 5) ( ref. ). Nie należy tego mylić last(), popełniłem ten błąd.
rocarvaj
1
groupby('id',as_index=False)zachowuje się również idjako felieton
Richard DiSalvo
55

To da ci drugi wiersz każdej grupy (indeksowany przez zero, n-ty (0) jest taki sam jak pierwszy ()):

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

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

wij
źródło
9
Jeśli chcesz uzyskać wielokrotności, na przykład pierwsze trzy, użyj sekwencji, takiej jak nth((0,1,2))lub nth(range(3)).
Ronan Paixão,
@ RonanPaixão: Jakoś kiedy podaję zasięg, wyrzuca błąd:TypeError: n needs to be an int or a list/set/tuple of ints
Peaceful
@Peaceful: czy używasz Pythona 3? Jeśli tak, range(3)nie zwraca listy, chyba że wpiszesz list(range(3)).
Ben
43

Sugerowałbym .nth(0)raczej użycie niż .first()jeśli potrzebujesz pierwszego rzędu.

Różnica między nimi polega na tym, jak radzą sobie z NaN, więc .nth(0)zwróci pierwszy wiersz grupy bez względu na wartości w tym wierszu, a .first()ostatecznie zwróci pierwszą wartość nie NaN w każdej kolumnie.

Np. Jeśli Twój zbiór danych to:

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

I

>>> df.groupby('id').first()
    value
id        
1    first
2    second
3    first
4    first
vital_dml
źródło
1
Słuszna uwaga. .head(1)wydaje się, że zachowuje się podobnie .nth(0), z wyjątkiem indeksu
Richard DiSalvo
2
Inną różnicą jest to, że nth (0) zachowa oryginalny indeks (jeśli as_index = False), a first () nie. Kiedyś była to dla mnie znacząca różnica, ponieważ potrzebowałem samego indeksu.
Oleg O
8

Jeśli potrzebujesz tylko pierwszego wiersza z każdej grupy, z którą możemy zrobić drop_duplicates, zwróć uwagę na domyślną metodę funkcji 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
BEN_YO
źródło
7

może tego chcesz

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.
źródło