pandas: crea columnas de tamaño único y sum después de agrupar por columnas múltiples

Tengo un dataframe en el que estoy haciendo groupby en 3 columnas y agregando la sum y el tamaño de las columnas numéricas. Después de ejecutar el código

df = pd.DataFrame.groupby(['year','cntry', 'state']).agg(['size','sum']) 

Estoy recibiendo algo como a continuación:

Imagen de datafram

Ahora quiero dividir mis sub-columnas de tamaño de las columnas principales y crear solo una columna de un solo tamaño, pero quiero mantener la sum de las columnas bajo los encabezados de las columnas principales. He intentado diferentes enfoques pero no he tenido éxito. Estos son los métodos que he intentado pero no puedo hacer que las cosas funcionen para mí:

¿Cómo contar el número de filas en un grupo en grupo de pandas por objeto?

Convertir un objeto Pandas GroupBy a DataFrame

Estaré agradecido si alguien me puede ayudar con esto.

Saludos,

Preparar

 d1 = pd.DataFrame(dict( year=np.random.choice((2014, 2015, 2016), 100), cntry=['United States' for _ in range(100)], State=np.random.choice(states, 100), Col1=np.random.randint(0, 20, 100), Col2=np.random.randint(0, 20, 100), Col3=np.random.randint(0, 20, 100), )) df = d1.groupby(['year', 'cntry', 'State']).agg(['size', 'sum']) df 

introduzca la descripción de la imagen aquí


Responder
La forma más fácil hubiera sido ejecutar solo el size después de groupby

 d1.groupby(['year', 'cntry', 'State']).size() year cntry State 2014 United States California 10 Florida 9 Massachusetts 8 Minnesota 5 2015 United States California 9 Florida 7 Massachusetts 4 Minnesota 11 2016 United States California 8 Florida 8 Massachusetts 11 Minnesota 10 dtype: int64 

Usar el df calculado.

 df.xs('size', axis=1, level=1) 

introduzca la descripción de la imagen aquí

Y eso sería útil si el size fuera diferente para cada columna. Pero como la columna de size es la misma para ['Col1', 'Col2', 'Col3'] , solo podemos hacer

 df[('Col1', 'size')] year cntry State 2014 United States California 10 Florida 9 Massachusetts 8 Minnesota 5 2015 United States California 9 Florida 7 Massachusetts 4 Minnesota 11 2016 United States California 8 Florida 8 Massachusetts 11 Minnesota 10 Name: (Col1, size), dtype: int64 

Vista combinada 1

 pd.concat([df[('Col1', 'size')].rename('size'), df.xs('sum', axis=1, level=1)], axis=1) 

introduzca la descripción de la imagen aquí


Vista combinada 2

 pd.concat([df[('Col1', 'size')].rename(('', 'size')), df.xs('sum', axis=1, level=1, drop_level=False)], axis=1) 

introduzca la descripción de la imagen aquí

piRSquared me ganó, pero si debe hacerlo de esta manera y desea mantener la alineación con las columnas y la sum o el tamaño debajo, podría reindexar las columnas para eliminar el valor del tamaño y luego agregar una nueva columna para contener el valor del tamaño.

Por ejemplo:

 group = df.groupby(['year', 'cntry','state']).agg(['sum','size']) mi = pd.MultiIndex.from_product([['Col1','Col2','Col3'],['sum']]) group = group.reindex_axis(mi,axis=1) sizes = df.groupby('state').size().values group['Tot'] = 0 group.columns = group.columns.set_levels(['sum','size'], level=1) group.Tot.size = sizes 

Acabará luciendo así:

  Col1 Col2 Col3 Tot sum sum sum size year cntry State 2015 US CA 20 0 4 1 FL 40 3 5 1 MASS 8 1 3 1 MN 12 2 3 1