在多索引 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:如何从对称的多索引数据框中提取值

如何从python中的数据框中删除多索引?

在熊猫多索引数据框中返回满足逻辑索引条件的每个组的最后一行[重复]

python pandas:重命名多索引数据框中的单列标签

panda的多索引的好处?