pandas: slice a MultiIndex by range of secondary index
pandas, python
Solution
As Robbie-Clarken answers, since 0.14 you can pass a slice in the tuple you pass to loc:
In [11]: s.loc[('b', slice(2, 10))]
Out[11]:
b 2 -0.65394
4 0.08227
dtype: float64
Indeed, you can pass a slice for each level:
In [12]: s.loc[(slice('a', 'b'), slice(2, 10))]
Out[12]:
a 5 0.27919
b 2 -0.65394
4 0.08227
dtype: float64
Note: the slice is inclusive.
Old answer:
You can also do this using:
s.ix[1:10, "b"]
(It's good practice to do in a single ix/loc/iloc since this version allows assignment.)
This answer was written prior to the introduction of iloc in early 2013, i.e. position/integer location - which may be preferred in this case. The reason it was created was to remove the ambiguity from integer-indexed pandas objects, and be more descriptive: "I'm slicing on position".
s["b"].iloc[1:10]
That said, I kinda disagree with the docs that ix is:
most robust and consistent way
it's not, the most consistent way is to describe what you're doing:
- use loc for labels
- use iloc for position
- use ix for both (if you really have to)
Remember the zen of python:
explicit is better than implicit
Problem
I have a series with a MultiIndex like this: ``` import numpy as np import pandas as pd buckets = np.repeat(['a','b','c'], [3,5,1]) sequence = [0,1,5,0,1,2,4,50,0] s = pd.Series( np.random.randn(len(sequence)), index=pd.MultiIndex.from_tuples(zip(buckets, sequence)) ) # In [6]: s # Out[6]: # a 0 -1.106047 # 1 1.665214 # 5 0.279190 # b 0 0.326364 # 1 0.900439 # 2 -0.653940 # 4 0.082270 # 50 -0.255482 # c 0 -0.091730 ``` I'd like to get the s['b'] values where the second index ('`sequence`') is between 2 and 10. Slicing on the first index works fine: ``` s['a':'b'] # Out[109]: # bucket value # a 0 1.828176 # 1 0.160496 # 5 0.401985 # b 0 -1.514268 # 1 -0.973915 # 2 1.285553 # 4 -0.194625 # 5 -0.144112 ``` But not on the second, at least by what seems to be the two most obvious ways: 1) This returns elements 1 through 4, with nothing to do with the index values ``` s['b'][1:10] # In [61]: s['b'][1:10] # Out[61]: # 1 0.900439 # 2 -0.653940 # 4 0.082270 # 50 -0.255482 ``` However, if I reverse the index and the first index is integer and the second index is a string, it works: ``` In [26]: s Out[26]: 0 a -0.126299 1 a 1.810928 5 a 0.571873 0 b -0.116108 1 b -0.712184 2 b -1.771264 4 b 0.148961 50 b 0.089683 0 c -0.582578 In [25]: s[0]['a':'b'] Out[25]: a -0.126299 b -0.116108 ```