pandas:按二级索引的范围切片MultiIndex

ala*_*ano 24 python pandas

我有一个像这样的MultiIndex系列:

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
Run Code Online (Sandbox Code Playgroud)

我想得到s ['b']值,其中第二个索引(' sequence')在2到10之间.

在第一个索引上切片工作正常:

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
Run Code Online (Sandbox Code Playgroud)

但不是第二种,至少通过两种最明显的方式:

1)返回元素1到4,与索引值无关

s['b'][1:10]

# In [61]: s['b'][1:10]
# Out[61]: 
# 1     0.900439
# 2    -0.653940
# 4     0.082270
# 50   -0.255482
Run Code Online (Sandbox Code Playgroud)

但是,如果我反转索引并且第一个索引是整数而第二个索引是字符串,则它可以工作:

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
Run Code Online (Sandbox Code Playgroud)

And*_*den 32

正如罗比 - 克拉肯回答的那样,从0.14开始,你可以传递给传递给loc的元组中的一个切片:

In [11]: s.loc[('b', slice(2, 10))]
Out[11]:
b  2   -0.65394
   4    0.08227
dtype: float64
Run Code Online (Sandbox Code Playgroud)

实际上,您可以为每个级别传递一个切片:

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
Run Code Online (Sandbox Code Playgroud)

注意:切片是包含的.


老答案:

你也可以这样做:

s.ix[1:10, "b"]
Run Code Online (Sandbox Code Playgroud)

(在单个ix/loc/iloc中这是一个很好的做法,因为这个版本允许赋值.)

这个答案是在2013年初引入iloc之前编写的,即位置/整数位置 - 在这种情况下可能是首选.创建它的原因是从整数索引的pandas对象中删除歧义,并且更具描述性:"我正在切换位置".

s["b"].iloc[1:10]
Run Code Online (Sandbox Code Playgroud)

那就是说,我有点不同意ix的文档:

最健壮,最一致的方式

事实并非如此,最一致的方式是描述你在做什么:

  • 使用loc作为标签
  • 使用iloc作为位置
  • 使用ix(如果你真的需要)

记住python禅宗:

显性比隐含更好

  • 答案中没有提到,但这正是我真正想要的:“您可以使用 `slice(None)` 来选择该级别的所有内容。您不需要指定所有更深的级别,它们将隐含为“切片(无)”。资料来源:[Pandas 文档](http://pandas.pydata.org/pandas-docs/stable/advanced.html#using-slicers)。 (2认同)

Eli*_*adL 9

从熊猫 0.15.0 开始,这有效:

s.loc['b', 2:10]
Run Code Online (Sandbox Code Playgroud)

输出:

b  2   -0.503023
   4    0.704880
dtype: float64
Run Code Online (Sandbox Code Playgroud)

DataFrame它略有不同(来源):

df.loc(axis=0)['b', 2:10]
Run Code Online (Sandbox Code Playgroud)

  • 这是最新的答案。它还很好地指出了黑白系列和 df 的细微差别。谢谢! (2认同)

小智 7

从pandas 0.14.0开始,可以通过提供包含切片对象的元组来对多索引对象进行切片:.loc

In [2]: s.loc[('b', slice(2, 10))]
Out[2]:
b  2   -1.206052
   4   -0.735682
dtype: float64
Run Code Online (Sandbox Code Playgroud)

  • `slice(None)` 选择该级别的所有内容。请参阅[使用切片器](https://pandas.pydata.org/pandas-docs/stable/user_guide/advanced.html#using-slicers)。 (2认同)