Marco de datos de Pandas: ¿cómo aplicar describe () a cada grupo y agregar a nuevas columnas?

df:

name score A 1 A 2 A 3 A 4 A 5 B 2 B 4 B 6 B 8 

Desea obtener el siguiente nuevo dataframe en la forma de abajo:

  name count mean std min 25% 50% 75% max A 5 3 .. .. .. .. .. .. B 4 5 .. .. .. .. .. .. 

¿Cómo extraer la información de df.describe () y reformatearla? Gracias

Definir algunos datos.

 In[1]: import pandas as pd import io data = """ name score A 1 A 2 A 3 A 4 A 5 B 2 B 4 B 6 B 8 """ df = pd.read_csv(io.StringIO(data), delimiter='\s+') print(df) 

.

 Out[1]: name score 0 A 1 1 A 2 2 A 3 3 A 4 4 A 5 5 B 2 6 B 4 7 B 6 8 B 8 

Solución

Un buen enfoque para este problema utiliza una expresión generadora (ver nota al pie) para permitir que pd.DataFrame() itere sobre los resultados de groupby , y construya el dataframe de estadísticas de resumen sobre la marcha:

 In[2]: df2 = pd.DataFrame(group.describe().rename(columns={'score':name}).squeeze() for name, group in df.groupby('name')) print(df2) 

.

 Out[2]: count mean std min 25% 50% 75% max A 5 3 1.581139 1 2.0 3 4.0 5 B 4 5 2.581989 2 3.5 5 6.5 8 

Aquí, la función de squeeze está squeeze una dimensión para convertir el Dataframe estadísticas de resumen de grupo de una columna en una Series .

Nota al pie : Una expresión generadora tiene la forma my_function(a) for a in iterator , o si el iterator nos devuelve tuples dos elementos, como en el caso de groupby : my_function(a,b) for a,b in iterator

Nada le gana a una sola línea:

 In [145]: print df.groupby('name').describe().reset_index().pivot(index='name', values='score', columns='level_1') level_1 25% 50% 75% count max mean min std name A 2.0 3 4.0 5 5 3 1 1.581139 B 3.5 5 6.5 4 8 5 2 2.581989 

hay incluso uno más corto 🙂

 print df.groupby('name').describe().unstack(1) 

Nada le gana a una sola línea:

En [145]:

imprimir df.groupby (‘nombre’). describe (). reset_index (). pivote (índice = ‘nombre’, valores = ‘puntaje’, columnas = ‘nivel_1’)

 import pandas as pd import io import numpy as np data = """ name score A 1 A 2 A 3 A 4 A 5 B 2 B 4 B 6 B 8 """ df = pd.read_csv(io.StringIO(data), delimiter='\s+') df2 = df.groupby('name').describe().reset_index().T.drop('name') arr = np.array(df2).reshape((4,8)) df2 = pd.DataFrame(arr[1:], index=['name','A','B']) print(df2) 

Eso te dará df2 como:

  0 1 2 3 4 5 6 7 name count mean std min 25% 50% 75% max A 5 3 1.58114 1 2 3 4 5 B 4 5 2.58199 2 3.5 5 6.5 8 

Bueno, conseguí lo que querías, pero no se escala muy bien.

 import pandas as pd name = ['a','a','a','a','a','b','b','b','b','b'] score = [1,2,3,4,5,2,4,6,8] d = pd.DataFrame(zip(name,score), columns=['Name','Score']) d = d.groupby('Name').describe() d = d.reset_index() df2 = pd.DataFrame(zip(d.level_1[8:], list(d.Score)[:8], list(d.Score)[8:]), columns = ['Name','A','B']).T print df2 0 1 2 3 4 5 6 7 Name count mean std min 25% 50% 75% max A 5 3 1.581139 1 2 3 4 5 B 4 5 2.581989 2 3.5 5 6.5 8 

La tabla se almacena en el dataframe llamado df

 df= pd.read_csv(io.StringIO(data),delimiter='\s+') 

Simplemente especifique el nombre de la columna y describe resultado requerido. De esta forma se calcula en cualquier columna.

 df.groupby('name')['score'].describe()