在多索引 Python Panda 数据框中过滤多个项目
Posted
技术标签:
【中文标题】在多索引 Python Panda 数据框中过滤多个项目【英文标题】:Filtering multiple items in a multi-index Python Panda dataframe 【发布时间】:2014-10-03 04:13:07 【问题描述】:我有下表:
注意:NSRCODE 和 PBL_AWI 都是索引的
注意:面积百分比列将被填写,只是尚未填写。
NSRCODE PBL_AWI Area % Of 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
如何过滤掉“PBL_AWI”索引中的项目? 例如我想保留 ['Lake', 'River', 'Upland']
【问题讨论】:
如果你的表名是 df,那么 df[df['PBL_AWI'] in ['Lake', 'River', 'Upland']] 或者 df[df['PBL_AWI'] = = 'Lake' 或 df['PBL_AWI'] == ''River 或 df['PBL_AWI'] == 'Upland'] 应该可以解决问题。过滤是非常基本的东西,你应该看到pandas.pydata.org/pandas-docs/stable/tutorials.html @Inox 我意识到过滤是我之前在单索引数据帧上做过的非常基本的事情。但是,在尝试上面的内容时,多索引数据框会产生“KeyError: u'no item named PBL_AWI'” 虽然@CTZhu 有正确的答案,但请注意,您可以使用@Inox 之类的解决方案,只需先执行df = df.reset_index()
。如果找不到更好的解决方案,我经常使用 MultiIndex 来解决这个问题。但我发现通常有更好的解决方案,只是不太容易被发现。
如果您有兴趣了解更多关于切片和过滤多索引数据帧的信息,请查看我的帖子:How do I slice or filter MultiIndex DataFrame levels?。谢谢!
【参考方案1】:
您可以将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'
【讨论】:
我发现第二种解决方案对类似问题很有用,选择多索引值大于给定数字的行:df[df.index.get_level_values('level_name') > 1]
。
第二个解决方案应该是答案,更清晰,不需要 np。
看看什么更快会很有趣。 np 已经是 pandas 的依赖项,所以几乎没有问题。【参考方案2】:
另一种(也许更干净)的方式可能是这个:
print(df[df.index.isin(['Lake', 'River', 'Upland'], level=1)])
参数level
指定索引号(以0开头)或索引名(这里:level='PBL_AWI'
)
【讨论】:
虽然此代码可能会解决问题,including an explanation 关于如何以及为什么解决问题将真正有助于提高您的帖子质量,并可能导致更多的赞成票。请记住,您正在为将来的读者回答问题,而不仅仅是现在提问的人。请edit您的回答添加解释并说明适用的限制和假设。 在这种情况下,已经对这些问题进行了丰富的讨论,如果受访者不想写一本关于该主题的教科书章节,我仍然觉得这个答案很有用。【参考方案3】:另外(来自here):
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'])
(未经面板和更高维度元素的测试,但我确实希望它可以工作)
【讨论】:
【参考方案4】:df.filter(regex=...,axis=...) 更加简洁,因为它适用于 index=0 和 column=1 轴。你不需要担心级别,你可以用正则表达式偷懒。索引过滤器的完整示例:
df.filter(regex='Lake|River|Upland',axis=0)
如果你转置它,并尝试对列进行过滤(默认为轴=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="\s2,").set_index(['NSRCODE', 'PBL_AWI'])
【讨论】:
【参考方案5】:使用.loc
的更简单方法是
df.loc[(slice(None),['Lake', 'River', 'Upland'])]
slice(None)
表示不对一级索引进行过滤。我们可以使用值列表过滤二级索引['Lake', 'River', 'Upland']
【讨论】:
这应该是公认的答案:根据定义,索引用于进行这种直接查找,无需创建中间布尔数组。 一开始对我不起作用,这就是:df.loc[(slice(None), ["Lake", "River", "Upland"]), :]
【参考方案6】:
这是对所提问题的一个轻微变体的回答,可能会为其他人节省一点时间。如果您正在寻找与您不知道其确切值的标签的通配符类型匹配,则可以使用以下内容:
q_labels = [ label for label in df.index.levels[1] if label.startswith('Q') ]
new_df = df[ df.index.isin(q_labels, level=1) ]
【讨论】:
以上是关于在多索引 Python Panda 数据框中过滤多个项目的主要内容,如果未能解决你的问题,请参考以下文章
将 numpy 数组复制到 Panda 多索引中(大小相同)
Python,pandas:如何从对称的多索引数据框中提取值