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?
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])
[~ # ~] 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.
À 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.
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.
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
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.