【问题标题】:Filter MultiIndex with Query Strings使用查询字符串过滤 MultiIndex
【发布时间】:2020-02-09 06:46:12
【问题描述】:

我有一个相当大的 DataFrame,比如 600 个索引,并且想要使用过滤条件来生成条件为真的 DataFrame 的简化版本。根据我所做的研究,当您将表达式应用于数据并且已经知道您正在操作的索引时,过滤效果很好。但是,我想要做的是将过滤条件应用于索引。请参阅下面的示例。

MultiIndex 为粗体,MultiIndex 名称为斜体。

我想沿着这些思路应用如下(或其他)标准:

df = df[MultiIndex.query('base == 115 & Al.isin(stn)')]

然后也许做这样的事情:

df = df.transpose()[MultiIndex.query('Fault.isin(cont)')].transpose

结果:

我认为基本上我正在尝试生成一个布尔列表来屏蔽 MultiIndex。如果有一种将熊猫查询应用于二维列表的快速方法?这是可以接受的。到目前为止,似乎一个选项是采用 MultiIndex,将其转换为 DataFrame,然后我可以应用过滤,因为我想获得 TF 数组。不过我担心这会很慢。

【问题讨论】:

标签: python pandas dataframe filtering multi-index


【解决方案1】:

如果您追求的是使用 df.query() 漂亮的语法对数据进行切片,那么您最好“取消透视”您的 DataFrame,将所有索引和列标签转换为常规字段。

您可以使用以下方法创建“unpivot”DataFrame:

df_unpivot = df.stack(level=[0, 1]).rename('value').reset_index()

这将产生一个如下所示的 DataFrame:

  season cont  stn   base value
0 Summer Fault Alpha  115   1.0
1 Summer Fault Beta   115   0.8
2 Summer Fault Gamma  230   0.7
3 Summer Trip  Alpha  115   1.2
4 Summer Trip  Beta   115   0.9
...

然后您可以查询:

df_unpivot.query(
    'cont.str.contains("Fault") and '
    'stn.str.contains("Al") and '
    'base == 115'
)

产生:

  season cont  stn   base value
0 Summer Fault Alpha  115   1.0
6 Winter Fault Alpha  115   0.7

您期望的两个值是哪个。

【讨论】:

  • 这是一个非常酷的方法,谢谢分享。我喜欢;我之所以拥有多索引格式的数据,是因为它很容易转换为我的 Excel 工作表。如果我需要报告以 115 为基数的故障,则未透视格式将很好地转换为报告就绪表。你对不旋转的性能有什么想法吗?我正在玩一些将列和索引转换为数据框的函数,它工作得很好。
  • 对于性能测量,%timeit 是您的朋友! ? 但是据说 Pandas 已经针对此类操作进行了优化,所以我希望它会非常快。查询数据后,您始终可以将其转回数据,以将其恢复为预期的演示格式。
  • 只是想补充一点,根据我的需要堆叠 df 的一般方法是:df1 = df.stack(level=list(range(df.index.nlevels))).rename('value').reset_index() ,然后您可以在查询后旋转(取消堆叠)以获得相同的格式:@987654328 @ 然后df2.columns = df2.columns.droplevel(0)
【解决方案2】:

如您所见,索引不适用于使用过滤器表达式进行查询。有 df.filter(),但它在 MultiIndex 上似乎并不能很好地工作。

您仍然可以将 MultiIndex 值过滤为 Python 元组的可迭代对象,然后使用 .loc 访问过滤后的结果。

这行得通:

rows = [(season, cont)
        for (season, cont) in df.index
        if 'Fault' in cont]
cols = [(stn, base)
        for (stn, base) in df.columns
        if base == 115 and 'Al' in stn]
df.loc[rows, cols]

【讨论】:

  • 感谢您回来。我的解决方案是将 MultiIndex 转换为 DataFrame;像这样:df_MI = index.to_frame() 然后bool_array = df_MI['seas'].str.contains('winter').values。我很想使用像df_MI.query('base < 200') 这样可爱的语法,因为它可以使链接操作变得简单易用。
  • @likethevegetable 我添加了一个单独的答案,关于以一种您可以轻松使用query() 的方式取消透视数据。您还可以在 query() 中使用 str.contains 进行子字符串匹配。
猜你喜欢
  • 1970-01-01
  • 2022-06-10
  • 2016-07-16
  • 1970-01-01
  • 1970-01-01
  • 2011-04-21
  • 1970-01-01
  • 2019-08-21
  • 2018-08-20
相关资源
最近更新 更多