为什么我在切片数据框中看到所有原始索引元素?

时间:2017-10-07 19:49:11

标签: python pandas dataframe indexing multi-index

我有一个像这样的多索引数据框:

import pandas as pd
import numpy as np


df = pd.DataFrame({'ind1': list('aaaaaaaaabbbbbbbbb'),
                   'ind2': list('cccdddeeecccdddeee'),
                   'ind3': list(range(3))*6,
                   'val1': list(range(100, 118)),
                   'val2': list(range(70, 88))})

df_mult = df.set_index(['ind1', 'ind2', 'ind3'])

                val1  val2
ind1 ind2 ind3            
a    c    0      100    70
          1      101    71
          2      102    72
     d    0      103    73
          1      104    74
          2      105    75
     e    0      106    76
          1      107    77
          2      108    78
b    c    0      109    79
          1      110    80
          2      111    81
     d    0      112    82
          1      113    83
          2      114    84
     e    0      115    85
          1      116    86
          2      117    87

我现在可以使用.loc这样的

选择它的一个子集
df_subs = df_mult.loc[pd.IndexSlice['a', ['c', 'd'], :], :]

给出了预期的

                val1  val2
ind1 ind2 ind3            
a    c    0      100    70
          1      101    71
          2      102    72
     d    0      103    73
          1      104    74
          2      105    75

我打印时

df_subs.index

我得到了

MultiIndex(levels=[[u'a', u'b'], [u'c', u'd', u'e'], [0, 1, 2]],
           labels=[[0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1], [0, 1, 2, 0, 1, 2]],
           names=[u'ind1', u'ind2', u'ind3'])

为什么0级中仍有b而不只是a

如果我想将索引的元素用于其他内容,这可能会成为一个问题。然后

df_subs.index.levels[0]

给了我

Index([u'a', u'b'], dtype='object', name=u'ind1')

然而,

df_subs.index.get_level_values('ind1').unique()

给了我

Index([u'a'], dtype='object', name=u'ind1')

看起来与我不一致。

这是一个错误还是预期的行为?

1 个答案:

答案 0 :(得分:3)

GitHub讨论了这种行为here

简而言之,您看到的级别不是根据您实际观察到的MultiIndex中的值计算的 - 在您首次设置MultiIndex后,未观察到的级别将通过索引保持不变。这允许在一些MultiIndex的所有视图和副本之间共享级别索引,这在内存方面是很好的 - 即,df_multdf_subs在内存中共享相同的底层级索引。

如果您想要重新计算级别以消除未使用的级别并创建新的MultiIndex,则可以使用MultiIndex.remove_unused_levels()

在你的情况下

>>> df_subs.index.remove_unused_levels().levels[0]
Index(['a'], dtype='object', name='ind1')