Ordenar los contenedores de los pandas cortados

Usando pandas cortar , puedo definir ubicaciones proporcionando los bordes y pandas crea ubicaciones como (a, b] .

Mi pregunta es ¿cómo puedo ordenar los contenedores (de la más baja a la más alta)?

 import numpy as np import pandas as pd y = pd.Series(np.random.randn(100)) x1 = pd.Series(np.sign(np.random.randn(100))) x2 = pd.cut(pd.Series(np.random.randn(100)), bins = [-3, -0.5, 0, 0.5, 3]) model = pd.concat([y, x1, x2], axis = 1, keys = ['Y', 'X1', 'X2']) 

Tengo un resultado intermedio donde se conserva el orden de los contenedores.

 int_output = model.groupby(['X1', 'X2']).mean().unstack() int_output.columns = int_output.columns.get_level_values(1) X2 (-3, -0.5] (-0.5, 0] (0, 0.5] (0.5, 3] X1 -1.0 0.101475 -0.344419 -0.482992 -0.015179 1.0 0.249961 0.484757 -0.066383 -0.249414 

Pero luego hago otras operaciones que cambian arbitrariamente el orden de los contenedores:

 output = pd.concat(int_output.to_dict('series'), axis = 1) (-0.5, 0] (-3, -0.5] (0, 0.5] (0.5, 3] X1 -1.0 -0.344419 0.101475 -0.482992 -0.015179 1.0 0.484757 0.249961 -0.066383 -0.249414 

Ahora me gustaría trazar los datos en un gráfico de barras, pero quiero que los contenedores se ordenen desde el más bajo (-3, -0.5) al más alto (0.5, 3].

Creo que puedo lograrlo manipulando la cadena, usando una división en “,” y luego limpiando los soportes, pero me gustaría saber si hay una mejor manera.

Hay un problema principal al perder el CategoricalIndex .

 np.random.seed(12456) y = pd.Series(np.random.randn(100)) x1 = pd.Series(np.sign(np.random.randn(100))) x2 = pd.cut(pd.Series(np.random.randn(100)), bins = [-3, -0.5, 0, 0.5, 3]) model = pd.concat([y, x1, x2], axis = 1, keys = ['Y', 'X1', 'X2']) int_output = model.groupby(['X1', 'X2']).mean().unstack() int_output.columns = int_output.columns.get_level_values(1) print (int_output) X2 (-3, -0.5] (-0.5, 0] (0, 0.5] (0.5, 3] X1 -1.0 0.230060 -0.079266 -0.079834 -0.064455 1.0 -0.451351 0.268688 0.020091 -0.280218 print (int_output.columns) CategoricalIndex(['(-3, -0.5]', '(-0.5, 0]', '(0, 0.5]', '(0.5, 3]'], categories=['(-3, -0.5]', '(-0.5, 0]', '(0, 0.5]', '(0.5, 3]'], ordered=True, name='X2', dtype='category') output = pd.concat(int_output.to_dict('series'), axis = 1) print (output) (-0.5, 0] (-3, -0.5] (0, 0.5] (0.5, 3] X1 -1.0 -0.079266 0.230060 -0.079834 -0.064455 1.0 0.268688 -0.451351 0.020091 -0.280218 print (output.columns) Index(['(-0.5, 0]', '(-3, -0.5]', '(0, 0.5]', '(0.5, 3]'], dtype='object') 

Una posible solución es extract primer número de output.columns , crear series de ayuda y ordenarlas. Últimas reindex columnas originales:

 cat = output.columns.str.extract('\((.*),', expand=False).astype(float) a = pd.Series(cat, index=output.columns).sort_values() print (a) (-3, -0.5] -3.0 (-0.5, 0] -0.5 (0, 0.5] 0.0 (0.5, 3] 0.5 dtype: float64 output = output.reindex(columns=a.index) print (output) (-3, -0.5] (-0.5, 0] (0, 0.5] (0.5, 3] X1 -1.0 0.230060 -0.079266 -0.079834 -0.064455 1.0 -0.451351 0.268688 0.020091 -0.280218 

Una solución fácil para el problema que ha resaltado anteriormente es simplemente reordenar las columnas:

 output[sorted(output.columns)] 

Hice una función para hacerlo.

 def dfsortbybins(df, col): """ param df: pandas dataframe param col: name of column containing bins """ d=dict(zip(bins,[float(s.split(',')[0].split('(')[1]) for s in bins])) df[f'{col} dfrankbybins']=df.apply(lambda x : d[x[col]] if not pd.isnull(x[col]) else x[col], axis=1) df=df.sort_values(f'{col} dfrankbybins').drop(f'{col} dfrankbybins',axis=1) return df