为什么Pandas DataFrame Slice的索引与其形状不同?

时间:2016-04-14 16:41:49

标签: python pandas indexing dataframe

我有一个DataFrame df1,它是df的一个切片。 df是多索引的,形状为(8,)。切片删除了df的第二级。当我执行df1.shape时,它会返回(4,) - 一切都很好 - 但是当我执行df1.index.levels[0]时,它会返回(4,)。怎么会发生这种情况?

In [ ]:       
arrays = [np.array(['bar', 'bar', 'baz', 'baz', 'foo', 'foo', 'qux', 'qux']),
            np.array(['one', 'two', 'one', 'two', 'one', 'two', 'one', 'two'])]


    df = pd.DataFrame(np.random.randn(8,2), index=arrays)
    df

Out [ ]:
            0        1
bar one   -0.447155  -0.323073
    two    0.115899  -0.015561
baz one   -0.272498  1.847073
    two   -0.399948  -0.264327
foo one    0.169687  -1.708543
    two    1.154434  0.878936
qux one    0.535721  0.437186
    two   -1.203431  0.568412

In [ ]:
    df1=df[df[1]>0]

Out [ ]:
            0           1
    baz one  -0.272498  1.847073
    foo two  1.154434   0.878936
    qux one  0.535721   0.437186
        two  -1.203431  0.568412

现在是奇怪的一点

In [ ]:
    df1=df[df[1]>0]
    print(df1.index.levels[0], df1.index.levels[0].shape)

Out [ ]:
    Index(['bar', 'baz', 'foo', 'qux'], dtype='object') (4,)

我发现这很奇怪,因为bar中没有显示df1。这背后的原因是什么?

我的猜测是复制/不复制,但我不明白为什么。

3 个答案:

答案 0 :(得分:3)

根据docs

  

注意MultiIndex的repr显示索引的所有已定义级别,即使它们实际未被使用也是如此。切片索引时,您可能会注意到这一点。 ...

     

这样做是为了避免重新计算级别,以使切片具有高性能。如果你想看到实际使用的水平......

使用仅使用的级别重建多索引

df1.index = pd.MultiIndex.from_tuples(df1.index)

答案 1 :(得分:2)

考虑两个指标:

In [59]: df.index
Out[59]: 
MultiIndex(levels=[[u'bar', u'baz', u'foo', u'qux'], [u'one', u'two']],
           labels=[[0, 0, 1, 1, 2, 2, 3, 3], [0, 1, 0, 1, 0, 1, 0, 1]])

In [58]: df1.index
Out[58]: 
MultiIndex(levels=[[u'bar', u'baz', u'foo', u'qux'], [u'one', u'two']],
           labels=[[1, 2, 3, 3], [0, 1, 0, 1]])

使用df1构建df1 = df[df[1]>0]时,Pandas可以构建df1.index 只是改变labels。而且,如果它不改变levels,那么 它不必重新编号labels。这就是df1.index包含bar的原因 即使df1未使用bar

您可以使用reset_index/set_index

重建索引
In [63]: df1.reset_index().set_index(['level_0', 'level_1']).index
Out[63]: 
MultiIndex(levels=[[u'baz', u'foo', u'qux'], [u'one', u'two']],
           labels=[[0, 1, 2, 2], [0, 1, 0, 1]],
           names=[u'level_0', u'level_1'])

- 或者使用Alexander's faster solutiondf1.index = pd.MultiIndex.from_tuples(df1.index) - 但是Pandas    默认情况下不会这样做可能是为了获得更好的性能。

答案 2 :(得分:1)

这是因为级别只是标签,它是决定该标签存在哪些标签的第二级值,例如在我的情况下:

In [2]:
arrays = [np.array(['bar', 'bar', 'baz', 'baz', 'foo', 'foo', 'qux', 'qux']),
            np.array(['one', 'two', 'one', 'two', 'one', 'two', 'one', 'two'])]
​
df = pd.DataFrame(np.random.randn(8,2), index=arrays)
df
​
Out[2]:
                0         1
bar one  1.226303  0.017598
    two  0.940893  1.491474
baz one  0.335430  1.178512
    two -1.006346 -0.733090
foo one -0.765838 -0.494056
    two -1.744994 -1.001641
qux one  0.177123 -0.969671
    two  0.544314 -0.026114

In [3]:    
df1=df[df[1]>0]
df1.index

Out[3]:
MultiIndex(levels=[['bar', 'baz', 'foo', 'qux'], ['one', 'two']],
           labels=[[0, 0, 1], [0, 1, 0]])

给出:

In [4]:
df1

Out[4]:
                0         1
bar one  1.226303  0.017598
    two  0.940893  1.491474
baz one  0.335430  1.178512

所以,如果你看一下索引:

MultiIndex(levels=[['bar', 'baz', 'foo', 'qux'], ['one', 'two']],
               labels=[[0, 0, 1], [0, 1, 0]])

值:labels=[[0, 0, 1], [0, 1, 0]是存在的级别值的值,这就是您看到所有4个标签并且形状为4的原因