过滤多索引 Pandas 数据框中的多个项目

问题描述 投票:0回答:8

我有下表:

NSRCODE  PBL_AWI          Area           
CM       BONS             44705.492941
         BTNN            253854.591990
         FONG             41625.590370
         FONS             16814.159680
         Lake             57124.819333
         River             1603.906642
         SONS            583958.444751
         STNN             45603.837177
         clearcut        106139.013930
         disturbed       127719.865675
         lowland         118795.578059
         upland         2701289.270193
LBH      BFNN            289207.169650
         BONS           9140084.716743
         BTNI             33713.160390
         BTNN          19748004.789040
         FONG           1687122.469691
         FONS           5169959.591270
         FTNI            317251.976160
         FTNN           6536472.869395
         Lake            258046.508310
         River            44262.807900
         SONS           4379097.677405
         burn regen      744773.210860
         clearcut         54066.756790
         disturbed       597561.471686
         lowland       12591619.141842
         upland        23843453.638117

注:

NSRCODE
PBL_AWI
都是索引。

如何搜索第

PBL_AWI
列中的值?例如,我想保留值
['Lake', 'River', 'Upland']

python pandas indexing filtering multi-index
8个回答
141
投票

您可以

get_level_values
与布尔切片结合使用。

In [50]:

print df[np.in1d(df.index.get_level_values(1), ['Lake', 'River', 'Upland'])]
                          Area
NSRCODE PBL_AWI               
CM      Lake      57124.819333
        River      1603.906642
LBH     Lake     258046.508310
        River     44262.807900

同一个想法可以有多种不同的表达方式,例如

df[df.index.get_level_values('PBL_AWI').isin(['Lake', 'River', 'Upland'])]

请注意,您的数据中有

'upland'
而不是
'Upland'


76
投票

另一种(也许更干净)的方式可能是这样的:

print(df[df.index.isin(['Lake', 'River', 'Upland'], level=1)])

参数

level
指定索引号(从0开始)或索引名称(这里:
level='PBL_AWI'


26
投票

使用

.loc
的更简单方法是

df.loc[(slice(None),['Lake', 'River', 'Upland']),:]

或系列

df.loc[(slice(None),['Lake', 'River', 'Upland'])]

slice(None)
表示对第一级索引不进行过滤。我们可以使用值列表过滤第二级索引
['Lake', 'River', 'Upland']


11
投票

df.filter(regex=...,axis=...) 更加简洁,因为它适用于index=0 和column=1 轴。你不需要担心级别,你可以用正则表达式来偷懒。索引过滤器的完整示例:

df.filter(regex='Lake|River|Upland',axis=0)

如果你转置它,并尝试过滤列(默认情况下 axis=1),它也可以工作:

df.T.filter(regex='Lake|River|Upland')

现在,使用正则表达式,您还可以轻松修复 Upland 的大小写问题:

upland = re.compile('Upland', re.IGNORECASE)
df.filter(regex=upland ,axis=0)

这是读取上面输入表的命令:

df = pd.read_csv(io.StringIO(inpute_table), sep="\s{2,}").set_index(['NSRCODE', 'PBL_AWI'])


9
投票

另外(来自这里):

def filter_by(df, constraints):
    """Filter MultiIndex by sublevels."""
    indexer = [constraints[name] if name in constraints else slice(None)
               for name in df.index.names]
    return df.loc[tuple(indexer)] if len(df.shape) == 1 else df.loc[tuple(indexer),]

pd.Series.filter_by = filter_by
pd.DataFrame.filter_by = filter_by

...用作

df.filter_by({'PBL_AWI' : ['Lake', 'River', 'Upland']})

(未经面板和更高维度元素的测试,但我确实希望它能够工作)


2
投票

您还可以使用

query
:

In [9]: df.query("PBL_AWI == ['Lake', 'River', 'Upland']")
Out[9]: 
                     Area
NSRCODE PBL_AWI          
CM      Lake     57124.82
        River     1603.91
LBH     Lake    258046.51
        River    44262.81

但是,由于区分大小写,将找不到“upland”(小写)。因此我建议使用

fullmatch
并设置
case=False
:

In [10]: df.query("PBL_AWI.str.fullmatch('Lake|River|Upland', case=False).values")
Out[10]: 
                       Area
NSRCODE PBL_AWI            
CM      Lake       57124.82
        River       1603.91
        upland   2701289.27
LBH     Lake      258046.51
        River      44262.81
        upland  23843453.64

0
投票

这是对所提问题的一个轻微变体的答案,可能会节省其他人一些时间。如果您正在寻找与您不知道其确切值的标签相匹配的通配符类型,您可以使用如下所示的内容:

q_labels = [ label for label in df.index.levels[1] if label.startswith('Q') ]
new_df = df[ df.index.isin(q_labels, level=1) ]

0
投票

对于简单切片,您还可以使用

:
来指定您想要该级别中的所有值。例如,我们不关心OP中第一个索引级别的值,因此我们使用
:

df.loc[:, ['Lake', 'upland'], :]
#      ^                         <--- for first index level
#          ^^^^^^^^^^^^^^^^      <--- filter for the second index level
#                             ^  <--- select all columns (if any)

pd.IndexSlice[]

对于更复杂的切片,可以使用

pd.IndexSlice[]
。例如,如果您还想选择列,则使用
pd.IndexSlice[]
指定哪部分是索引切片,哪部分是列选择。

df.loc[pd.IndexSlice[:, ['Lake', 'upland']], ['Area']]
#                    ^                               <--- slice for first index level
#                        ^^^^^^^^^^^^^^^^            <--- slice for second index level
#                                             ^^^^   <--- column selection

根据OP中给出的输入,我们得到以下结果:

也可以按一级、二级、列进行选择。

df.loc[pd.IndexSlice['CM', ['Lake', 'upland']], ['Area']]

© www.soinside.com 2019 - 2024. All rights reserved.