Jak uzyskać dostęp do pandas groupby dataframe według klucza

154

Jak uzyskać dostęp do odpowiedniej ramki danych typu groupby w obiekcie typu groupby za pomocą klucza?

Z następującą grupą:

rand = np.random.RandomState(1)
df = pd.DataFrame({'A': ['foo', 'bar'] * 3,
                   'B': rand.randn(6),
                   'C': rand.randint(0, 20, 6)})
gb = df.groupby(['A'])

Mogę go iterować, aby uzyskać klucze i grupy:

In [11]: for k, gp in gb:
             print 'key=' + str(k)
             print gp
key=bar
     A         B   C
1  bar -0.611756  18
3  bar -1.072969  10
5  bar -2.301539  18
key=foo
     A         B   C
0  foo  1.624345   5
2  foo -0.528172  11
4  foo  0.865408  14

Chciałbym mieć dostęp do grupy za pomocą jej klucza:

In [12]: gb['foo']
Out[12]:  
     A         B   C
0  foo  1.624345   5
2  foo -0.528172  11
4  foo  0.865408  14

Ale kiedy próbuję to zrobić, gb[('foo',)]otrzymuję ten dziwny pandas.core.groupby.DataFrameGroupByobiekt, który wydaje się nie mieć żadnych metod odpowiadających ramce DataFrame, której chcę.

Najlepsze, o czym mogłem pomyśleć, to:

In [13]: def gb_df_key(gb, key, orig_df):
             ix = gb.indices[key]
             return orig_df.ix[ix]

         gb_df_key(gb, 'foo', df)
Out[13]:
     A         B   C
0  foo  1.624345   5
2  foo -0.528172  11
4  foo  0.865408  14  

ale to trochę paskudne, biorąc pod uwagę, jak fajne są zazwyczaj pandy w takich sprawach.
Jaki jest na to wbudowany sposób?

beardc
źródło

Odpowiedzi:

192

Możesz użyć get_groupmetody:

In [21]: gb.get_group('foo')
Out[21]: 
     A         B   C
0  foo  1.624345   5
2  foo -0.528172  11
4  foo  0.865408  14

Uwaga: Nie wymaga to tworzenia pośredniego słownika / kopii każdej subdataframe dla każdej grupy, więc będzie znacznie bardziej wydajne w pamięci niż tworzenie naiwnego słownika z dict(iter(gb)). Dzieje się tak, ponieważ wykorzystuje struktury danych już dostępne w obiekcie grupowania.


Możesz wybrać różne kolumny, używając podziału na grupy:

In [22]: gb[["A", "B"]].get_group("foo")
Out[22]:
     A         B
0  foo  1.624345
2  foo -0.528172
4  foo  0.865408

In [23]: gb["C"].get_group("foo")
Out[23]:
0     5
2    11
4    14
Name: C, dtype: int64
Andy Hayden
źródło
72

Wes McKinney (autor pand) w Python for Data Analysis podaje następujący przepis:

groups = dict(list(gb))

która zwraca słownik, którego kluczami są etykiety grup i których wartości to DataFrames, tj

groups['foo']

przyniesie to, czego szukasz:

     A         B   C
0  foo  1.624345   5
2  foo -0.528172  11
4  foo  0.865408  14
JD Margulici
źródło
1
Dziękuję, jest to bardzo przydatne. Jak mogę zmodyfikować kod, aby utworzyć groups = dict(list(gb))tylko kolumnę sklepu C? Powiedzmy, że nie interesują mnie inne kolumny i dlatego nie chcę ich przechowywać.
Zhubarb
5
Odpowiedź:dict(list( df.groupby(['A'])['C'] ))
Zhubarb,
4
Uwaga: jest bardziej wydajny (ale równoważny) w użyciu dict(iter(g)). (chociaż get_groupjest to najlepszy sposób / ponieważ nie wymaga tworzenia słownika / trzyma w pandach!: D)
Andy Hayden
Nie mogłem użyć grup (dict (list (gb)), ale możesz utworzyć słownik w następujący sposób: gb_dict = {str(indx): str(val) for indx in gb.indx for val in gb.some_key}a następnie pobrać wartość za pośrednictwemgb_dict[some_key]
user2476665
Po prostu użyj get_group(), ten przepis nie był potrzebny od lat.
smci
20

Zamiast

gb.get_group('foo')

Wolę używać gb.groups

df.loc[gb.groups['foo']]

Ponieważ w ten sposób możesz również wybrać wiele kolumn. na przykład:

df.loc[gb.groups['foo'],('A','B')]
LegitMe
źródło
4
Uwaga: możesz wybrać różne kolumny za pomocą gb[["A", "B"]].get_group("foo").
Andy Hayden
6
gb = df.groupby(['A'])

gb_groups = grouped_df.groups

Jeśli szukasz selektywnych obiektów do grupowania, wykonaj: gb_groups.keys () i wprowadź żądany klucz do następującej listy_kluczy.

gb_groups.keys()

key_list = [key1, key2, key3 and so on...]

for key, values in gb_groups.iteritems():
    if key in key_list:
        print df.ix[values], "\n"
Surya
źródło
1

Szukałem sposobu na próbkowanie kilku członków GroupBy obj - musiałem odpowiedzieć na opublikowane pytanie, aby to zrobić.

utwórz obiekt grupowania

grouped = df.groupby('some_key')

wybierz N ramek danych i pobierz ich oznaczenia

sampled_df_i  = random.sample(grouped.indicies, N)

chwyć grupy

df_list  = map(lambda df_i: grouped.get_group(df_i), sampled_df_i)

opcjonalnie - przekształć to wszystko z powrotem w pojedynczy obiekt dataframe

sampled_df = pd.concat(df_list, axis=0, join='outer')
meyerson
źródło
1
To nie działa: sampled_df_i = random.sample(grouped.indicies, N)
Irene
@irene - czy możesz podać link do dłuższego przykładu / szerszego kontekstu?
Meyerson
Otrzymuję następujący błąd:AttributeError: 'DataFrameGroupBy' object has no attribute 'indicies'
Irene