我有下表:
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']
。
您可以
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'
另一种(也许更干净)的方式可能是这样的:
print(df[df.index.isin(['Lake', 'River', 'Upland'], level=1)])
参数
level
指定索引号(从0开始)或索引名称(这里:level='PBL_AWI'
)
使用
.loc
的更简单方法是
df.loc[(slice(None),['Lake', 'River', 'Upland']),:]
或系列
df.loc[(slice(None),['Lake', 'River', 'Upland'])]
slice(None)
表示对第一级索引不进行过滤。我们可以使用值列表过滤第二级索引['Lake', 'River', 'Upland']
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'])
另外(来自这里):
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']})
(未经面板和更高维度元素的测试,但我确实希望它能够工作)
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
这是对所提问题的一个轻微变体的答案,可能会节省其他人一些时间。如果您正在寻找与您不知道其确切值的标签相匹配的通配符类型,您可以使用如下所示的内容:
q_labels = [ label for label in df.index.levels[1] if label.startswith('Q') ]
new_df = df[ df.index.isin(q_labels, level=1) ]
对于简单切片,您还可以使用
:
来指定您想要该级别中的所有值。例如,我们不关心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']]