Ordenar pandas dataframe tanto en los valores de una columna y el índice?

¿Es posible ordenar el dataframe de pandas por valores de una columna, pero también por índice?

Si ordena un dataframe de pandas por valores de una columna, puede obtener el dataframe resultante ordenado por la columna, pero desafortunadamente, ve el orden del índice de su dataframe desordenado dentro del mismo valor de una columna ordenada.

Entonces, ¿puedo ordenar un dataframe por una columna, como la columna llamada count pero también ordenarlos por el valor del índice? ¿Y también es posible ordenar una columna por orden descendente, pero mientras que ordenar un índice por orden ascendente?

Sé cómo ordenar varias columnas en el dataframe, y también sé que puedo lograr lo que estoy pidiendo aquí primero reset_index() el índice y reset_index() , y luego crear el índice nuevamente. ¿Pero es la forma más intuitiva y eficiente de hacerlo?

EDITAR En pandas 0.23 puedes hacerlo directamente, ver la respuesta de OmerB.


Me atrevería a decir que la forma más sencilla es simplemente copiar su índice en una columna y luego ordenar por ambas.

 df['colFromIndex'] = df.index df = df.sort(['count', 'colFromIndex']) 

También preferiría poder hacer algo como df.sort(['count', 'index']) , pero por supuesto eso no funciona.

Pandas 0.23 finalmente te lleva allí 😀

Ahora puede pasar los nombres de índice (y no solo los nombres de columna) como parámetros a sort_values . Por lo tanto, este one-liner funciona:

 df = df.sort_values(by = ['MyCol', 'MyIdx'], ascending = [False, True]) 

Y si su índice es actualmente sin nombre:

 df = df.rename_axis('MyIdx').sort_values(by = ['MyCol', 'MyIdx'], ascending = [False, True]) 

A partir de la versión de pandas 0.22.

Puede establecer temporalmente la columna como un índice, ordenar el índice en esa columna y luego restablecer. Por defecto mantendrá el orden del índice existente:

 df = df.set_index('column_name', append=True).sort_index(level=1).reset_index(level=1) 

Creo que lo anterior podría hacerse con opciones ‘in situ’ pero creo que es más fácil de leer que lo anterior.

Para ordenar una columna descendente, mientras mantiene el índice ascendente:

 import pandas as pd df = pd.DataFrame(index=range(5), data={'c': [4,2,2,4,2]}) df.index = df.index[::-1] print df.sort(column='c', ascending=False) 

Salida:

  c 1 4 4 4 0 2 2 2 3 2 

Puedes usar una combinación de groupby y aplicar:

 In [2]: df = pd.DataFrame({ 'transID': range(8), 'Location': ['New York','Chicago','New York','New York','Atlanta','Los Angeles', 'Chicago','Atlanta'], 'Sales': np.random.randint(0,10000,8)}).set_index('transID') In [3]: df Out[3]: Location Sales transID 0 New York 1082 1 Chicago 1664 2 New York 692 3 New York 5669 4 Atlanta 7715 5 Los Angeles 987 6 Chicago 4085 7 Atlanta 2927 In [4]: df.groupby('Location').apply(lambda d: d.sort()).reset_index('Location',drop=True) Out[4]: Location Sales transID 4 Atlanta 7715 7 Atlanta 2927 1 Chicago 1664 6 Chicago 4085 5 Los Angeles 987 0 New York 1082 2 New York 692 3 New York 5669 

Dejo caer ‘Ubicación’ en la última línea porque groupby inserta los niveles agrupados en las primeras posiciones en el índice. Ordenar y luego soltarlos conserva el orden ordenado.

Puede usar el parámetro ascendente en sort_index, pero debe pasarlo como una lista para que funcione correctamente a partir de pandas 0.22.0.

 import pandas as pd import numpy as np df = pd.DataFrame({'idx_0':[2]*6+[1]*5, 'idx_1':[6,4,2,10,18,5,11,1,7,9,3], 'value_1':np.arange(11,0,-1), 'MyName':list('SORTEDFRAME')}) df = df.set_index(['idx_0','idx_1']) df 

Salida:

  MyName value_1 idx_0 idx_1 2 6 S 11 4 O 10 2 R 9 10 T 8 18 E 7 5 D 6 1 11 F 5 1 R 4 7 A 3 9 M 2 3 E 1 

La clasificación por valores e índice debe obtener “FRAMESORTED” en lugar de “SORTEDFRAME”

 df.sort_values('value_1', ascending=False)\ .sort_index(level=0, ascending=[True]) 

Salida:

  MyName value_1 idx_0 idx_1 1 11 F 5 1 R 4 7 A 3 9 M 2 3 E 1 2 6 S 11 4 O 10 2 R 9 10 T 8 18 E 7 5 D 6 

Tenga en cuenta que debe pasar el parámetro ascending en sort_index como una lista y no como un escalar. No funcionará.

Creo que el orden original de sort_values se mantiene incluso cuando se aplica sort_index , así que esto debería funcionar:

 df.sort_values('count', ascending=False).sort_index(level=[index_level1, index_level2]) 

Resuelvo este problema de la siguiente manera:

 df.to_csv('df.csv', index = False) df = df.read_csv('df.csv')