web-dev-qa-db-fra.com

Trier pandas dataframe à la fois sur les valeurs d'une colonne et d'un index?

Est-il possible de trier pandas dataframe par valeurs d'une colonne, mais aussi par index?

Si vous triez un pandas dataframe par les valeurs d'une colonne, vous pouvez obtenir le dataframe résultant trié par la colonne, mais malheureusement, vous voyez l'ordre de l'index de votre dataframe dans la même valeur d'un colonne triée.

Alors, puis-je trier une trame de données par une colonne, telle que la colonne nommée count mais aussi la trier par la valeur de l'index? Et est-il également possible de trier une colonne par ordre décroissant, mais alors de trier un index par ordre croissant?

Je sais comment trier plusieurs colonnes dans la trame de données, et je sais également que je peux réaliser ce que je demande ici en commençant par reset_index() l'index et en le triant, puis en créant à nouveau l'index. Mais est-ce une manière plus intuitive et efficace de le faire?

33
Blaszard

Pandas 0.2 vous y arrive enfin :-D

Vous pouvez maintenant passer des noms d'index (et pas seulement des noms de colonnes) en tant que paramètres à sort_values. Donc, ce one-liner fonctionne:

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

Et si votre index est actuellement sans nom:

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

[~ # ~] modifier [~ # ~] Dans pandas 0,23 vous pouvez simplement le faire directement - voir OmerB's réponse .


J'oserais que le moyen le plus simple est de simplement copier votre index dans une colonne, puis de trier par les deux.

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

Je préférerais également pouvoir simplement faire quelque chose comme df.sort(['count', 'index']), mais bien sûr, cela ne fonctionne pas.

28
fantabolous

À partir de pandas version 0.22.

Vous pouvez définir temporairement la colonne comme un index, trier l'index sur cette colonne, puis réinitialiser. Par défaut, il conservera l'ordre de l'index existant:

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

Je pense que ce qui précède pourrait être fait avec des options "sur place" mais je pense qu'il est plus facile à lire comme ci-dessus.

6
Iain D

Vous pouvez utiliser une combinaison de groupby et appliquer:

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

Je laisse tomber "Location" à la dernière ligne car groupby insère les niveaux groupés dans les premières positions de l'index. Les trier puis les supprimer conserve l'ordre de tri.

1
delgadom

Pour trier une colonne en ordre décroissant, tout en maintenant l'index en ordre croissant:

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)

Production:

   c
1  4
4  4
0  2
2  2
3  2
1
cyborg

Vous pouvez utiliser le paramètre croissant dans sort_index, mais vous devez le passer sous forme de liste pour qu'il fonctionne correctement à 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

Production:

            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

Le tri par valeurs et index devrait obtenir "FRAMESORTED" au lieu de "SORTEDFRAME"

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

Production:

            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

Notez que vous devez passer le paramètre ascending dans sort_index comme liste et non comme scalaire. Ça ne marchera pas.

1
Scott Boston