Cómo acceder a los pandas groupby dataframe por clave

154

¿Cómo accedo al marco de datos groupby correspondiente en un objeto groupby mediante la clave?

Con el siguiente groupby:

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'])

Puedo recorrerlo para obtener las claves y los grupos:

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

Me gustaría poder acceder a un grupo por su clave:

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

Pero cuando trato de hacer eso gb[('foo',)]obtengo este pandas.core.groupby.DataFrameGroupByobjeto extraño que no parece tener ningún método que corresponda al DataFrame que quiero.

Lo mejor que se me ocurre es:

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  

pero esto es un poco desagradable, considerando lo buenos que suelen ser los pandas en estas cosas.
¿Cuál es la forma integrada de hacer esto?

beardc
fuente

Respuestas:

192

Puedes usar el get_groupmétodo:

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

Nota: Esto no requiere crear un diccionario / copia intermedios de cada subdataframe para cada grupo, por lo que será mucho más eficiente en la memoria que crear un diccionario ingenuo dict(iter(gb)). Esto se debe a que utiliza estructuras de datos ya disponibles en el objeto groupby.


Puede seleccionar diferentes columnas usando la división en grupo:

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

Wes McKinney (autor de los pandas) en Python for Data Analysis proporciona la siguiente receta:

groups = dict(list(gb))

que devuelve un diccionario cuyas claves son las etiquetas de su grupo y cuyos valores son DataFrames, es decir

groups['foo']

le dará lo que está buscando:

     A         B   C
0  foo  1.624345   5
2  foo -0.528172  11
4  foo  0.865408  14
JD Margulici
fuente
1
Gracias, esto es muy útil. ¿Cómo puedo modificar el código para que groups = dict(list(gb))solo almacene la columna C? Digamos que no estoy interesado en las otras columnas y, por lo tanto, no quiero almacenarlas.
Zhubarb
55
Respuesta:dict(list( df.groupby(['A'])['C'] ))
Zhubarb
44
Nota: es más eficiente (pero equivalente) de usar dict(iter(g)). (¡aunque get_groupes la mejor manera / ya que no implica crear un diccionario / te mantiene en pandas!: D)
Andy Hayden
No pude usar grupos (dict (list (gb)) pero puede crear un diccionario de la siguiente manera: gb_dict = {str(indx): str(val) for indx in gb.indx for val in gb.some_key}y luego recuperar el valor a través degb_dict[some_key]
user2476665
Solo use get_group(), esta receta no ha sido necesaria por años.
smci
20

Más bien que

gb.get_group('foo')

Prefiero usar gb.groups

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

Porque de esta manera también puedes elegir varias columnas. por ejemplo:

df.loc[gb.groups['foo'],('A','B')]
LegitMe
fuente
44
Nota: Puede seleccionar diferentes columnas usando gb[["A", "B"]].get_group("foo").
Andy Hayden
6
gb = df.groupby(['A'])

gb_groups = grouped_df.groups

Si está buscando un grupo selectivo por objetos, entonces: gb_groups.keys (), e ingrese la clave deseada en la siguiente lista de claves.

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

Estaba buscando una forma de probar algunos miembros del grupo. Obj. Tenía que abordar la pregunta publicada para hacer esto.

crear objeto groupby

grouped = df.groupby('some_key')

elija N marcos de datos y tome sus indicaciones

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

agarra los grupos

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

opcionalmente: vuelva a convertir todo en un solo objeto de marco de datos

sampled_df = pd.concat(df_list, axis=0, join='outer')
meyerson
fuente
1
Esto no funciona:sampled_df_i = random.sample(grouped.indicies, N)
Irene
@irene: ¿puede proporcionar un enlace a un ejemplo más largo / más contexto?
meyerson
Me sale el siguiente error:AttributeError: 'DataFrameGroupBy' object has no attribute 'indicies'
Irene