Reputation: 1777
Is there a way to reorder specific levels within the columns index in a Pandas dataframe based on my personal preference (e.g., by an ordered list)?
In [130]: frame = pd.DataFrame({
...: ('TWO','thing1'):[1,2,3,4],
...: ('TWO','thing4'):[1,2,3,4],
...: ('DARK','thing1'):[0.1,0.2,1,2],
...: ('ANTS','thing3'):['a','e','i','o'],
...: ('ANTS','thing1'):['a','e','i','o']})
In [131]: frame
Out[131]:
ANTS DARK TWO
thing1 thing3 thing1 thing1 thing4
0 a a 0.1 1 1
1 e e 0.2 2 2
2 i i 1.0 3 3
3 o o 2.0 4 4
My list is then based on a separately generated list. Important to note that I don't know either level 0
or level 1
index labels - they are variables.
In [132]: sort_list = ['DARK', 'ANTS', 'TWO']
If I then try and pass this list in the context of frame = frame[sort_list]
or .reindex(columns=sort_list)
it throws Expected tuple, got str
for obvious reasons. Here are the solutions that worked on a single level index.
What I'd like to do is only sort on the top level and leave the second level as is. The final dataframe looking like this...
DARK ANTS TWO
thing1 thing1 thing3 thing1 thing4
0.1 a a 1 1
0.2 e e 2 2
1.0 i i 3 3
2.0 o o 4 4
Upvotes: 2
Views: 752
Reputation: 294278
You can sort the index then slice
frame.sort_index(axis=1, level=1)[['DARK', 'ANTS', 'TWO']]
DARK ANTS TWO
thing1 thing1 thing3 thing1 thing4
0 0.1 a a 1 1
1 0.2 e e 2 2
2 1.0 i i 3 3
3 2.0 o o 4 4
Set the first level of the columns to be categorical that is ordered
frame.columns = frame.columns.set_levels(
pd.CategoricalIndex(
frame.columns.levels[0],
['DARK', 'ANTS', 'TWO'],
ordered=True
), level=0
)
frame.sort_index(axis=1)
DARK ANTS TWO
thing1 thing1 thing3 thing1 thing4
0 0.1 a a 1 1
1 0.2 e e 2 2
2 1.0 i i 3 3
3 2.0 o o 4 4
Upvotes: 3
Reputation: 323266
You can using reindex
frame.reindex(sort_list, level=0, axis=1)
Out[126]:
DARK ANTS TWO
thing1 thing1 thing3 thing1 thing4
0 0.1 a a 1 1
1 0.2 e e 2 2
2 1.0 i i 3 3
3 2.0 o o 4 4
Upvotes: 4