带有 MultiIndex 数据帧的 .loc 和 .iloc

新手上路,请多包涵

当索引一个 MultiIndex-ed DataFrame 时,似乎 .iloc 假设您引用索引的“内部级别”,而 .loc 看起来在外部级别。

例如:

 np.random.seed(123)
iterables = [['bar', 'baz', 'foo', 'qux'], ['one', 'two']]
idx = pd.MultiIndex.from_product(iterables, names=['first', 'second'])
df = pd.DataFrame(np.random.randn(8, 4), index=idx)

# .loc looks at the outer index:

print(df.loc['qux'])
# df.loc['two'] would throw KeyError
              0        1        2        3
second
one    -1.25388 -0.63775  0.90711 -1.42868
two    -0.14007 -0.86175 -0.25562 -2.79859

# while .iloc looks at the inner index:

print(df.iloc[-1])
0   -0.14007
1   -0.86175
2   -0.25562
3   -2.79859
Name: (qux, two), dtype: float64

两个问题:

首先,这是为什么?这是故意的设计决定吗?

其次,我可以使用 .iloc 来引用索引的外部级别,以产生以下结果吗?我知道我可以先用 get_level_values 找到索引的最后一个成员,然后 .loc 用那个索引,但是如果可以更直接地完成它,或者用 funky .iloc 专门为这种情况设计的语法或一些现有函数。

 # df.iloc[-1]
qux   one     0.89071  1.75489  1.49564  1.06939
      two    -0.77271  0.79486  0.31427 -1.32627

原文由 Brad Solomon 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 584
2 个回答

是的,这是一个 深思熟虑的设计决定

.iloc 是一个严格的位置索引器,它 根本不 考虑结构,只考虑第一个实际行为。 … .loc 确实 考虑了级别行为。 [强调]

因此,不可能以灵活的方式使用 .iloc 在问题中给出期望的结果。在几个类似的问题中使用的最接近的解决方法是

print(df.loc[[df.index.get_level_values(0)[-1]]])
                    0        1        2        3
first second
qux   one    -1.25388 -0.63775  0.90711 -1.42868
      two    -0.14007 -0.86175 -0.25562 -2.79859

使用 双括号 将保留第一个索引级别。

原文由 Brad Solomon 发布,翻译遵循 CC BY-SA 3.0 许可协议

您可以使用:

 df.iloc[[6, 7], :]
Out[1]:
                     0         1         2         3
first second
qux   one    -1.253881 -0.637752  0.907105 -1.428681
      two    -0.140069 -0.861755 -0.255619 -2.798589

其中 [6, 7] 对应于这些行的实际行索引,如下所示:

 df.reset_index()
Out[]:
  first second         0         1         2         3
0   bar    one -1.085631  0.997345  0.282978 -1.506295
1   bar    two -0.578600  1.651437 -2.426679 -0.428913
2   baz    one  1.265936 -0.866740 -0.678886 -0.094709
3   baz    two  1.491390 -0.638902 -0.443982 -0.434351
4   foo    one  2.205930  2.186786  1.004054  0.386186
5   foo    two  0.737369  1.490732 -0.935834  1.175829
6   qux    one -1.253881 -0.637752  0.907105 -1.428681
7   qux    two -0.140069 -0.861755 -0.255619 -2.798589

这也适用于 df.iloc[[-2, -1], :]df.iloc[range(-2, 0), :]


编辑:把它变成一个更通用的解决方案

然后就有可能得到一个泛型函数:

 def multindex_iloc(df, index):
    label = df.index.levels[0][index]
    return df.iloc[df.index.get_loc(label)]

multiindex_loc(df, -1)
Out[]:
                     0         1         2         3
first second
qux   one    -1.253881 -0.637752  0.907105 -1.428681
      two    -0.140069 -0.861755 -0.255619 -2.798589

multiindex_loc(df, 2)
Out[]:
                     0         1         2         3
first second
foo   one     2.205930  2.186786  1.004054  0.386186
      two     0.737369  1.490732 -0.935834  1.175829

原文由 FabienP 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题