Question
Why the sorting using pd.Series.sort_index does not seem to work when using categorical index? How would one sort the index of the multi-index pd.Series using other sort order than alphabetical/numerical?
MWE
Setup code
import pandas as pd
import numpy as np
d = {
'Card': [
'Visa', 'Visa', 'Master Card', 'Master Card', 'Visa', 'Master Card',
'Visa', 'Visa', 'Master Card', 'Visa', 'Master Card', 'Visa', 'Visa',
'Master Card', 'Master Card', 'Visa', 'Master Card', 'Visa', 'Visa',
'Master Card', 'Visa', 'Master Card', 'Master Card', 'Master Card',
'Master Card', 'Master Card', 'Master Card', 'Visa', 'Visa'
],
'Year': [
'Three', 'Three', 'Seven', 'Three', 'Three', 'Seven', 'Seven', 'Seven',
'Three', 'Seven', 'Three', 'Three', 'Three', 'Seven', 'Three', 'Three',
'Seven', 'Seven', 'Seven', 'Three', 'Seven', 'Three', 'Five', 'One',
'One', 'Two', 'Four', 'Six', 'Six'
],
'Value': [
45, 13, 52, 321, 31, 1231, 876, 231, 4, 213, 123, 45, 321, 1, 123, 52,
736, 35, 900, 301, 374, 9, 294, 337, 4465, 321, 755, 22, 8
]
}
df = pd.DataFrame(d)
grp_cols = ['Card', 'Year']
ser_val = df.groupby(grp_cols)['Value'].mean()
Using naively just sort_index, the data looks like this:
In [2]: ser_val.sort_index()
Out[2]:
Card Year
Master Card Five 294.000000
Four 755.000000
One 2401.000000
Seven 505.000000
Three 146.833333
Two 321.000000
Visa Seven 438.166667
Six 15.000000
Three 84.500000
Name: Value, dtype: float64
you can see that the columns are sorted alphabetically. Now, I want to force the ordering. For that, I try:
categories_order = ['One', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven']
categories = pd.Categorical(ser_val.index.levels[1].values,
categories=categories_order,
ordered=True)
ser_val.index.set_levels(categories, level='Year', inplace=True)
again, after sorting, the data looks like this (again, alphabetical order)
In [3]: ser_val.sort_index()
Out[3]:
Card Year
Master Card Five 294.000000
Four 755.000000
One 2401.000000
Seven 505.000000
Three 146.833333
Two 321.000000
Visa Seven 438.166667
Six 15.000000
Three 84.500000
Name: Value, dtype: float64
I know that if I convert the data into pandas.DataFrame and sort there, it works, like this:
df_val = ser_val.reset_index().sort_values(grp_cols)
df_val['Year'] = pd.Categorical(df_val['Year'].values,
categories_order,
ordered=True)
df_val = df_val.sort_values(grp_cols).set_index(grp_cols)
In [5]: df_val
Out[5]:
Value
Card Year
Master Card One 2401.000000
Two 321.000000
Three 146.833333
Four 755.000000
Five 294.000000
Seven 505.000000
Visa Three 84.500000
Six 15.000000
Seven 438.166667
Why won't the pd.Series sort with categorical data?
I am using pandas 1.0.5 in Python 3.7.3 64-bit