pandas loc用多索引修改dataFrame?

时间:2016-10-28 09:07:29

标签: python pandas indexing multi-index

我发现了loc的一些有趣行为(bug?),带有多索引数据框,其中第一个索引是单个的。使用loc(第一次)后,第一个索引(多索引)消失了!

示例:

In [1]: import pandas as pd

In [2]: x = pd.DataFrame({'idx1':[1]*10, 'idx2':[1]*5+[2]*5, 'idx3':range(5)+range(5), 'data': [1]*10})

In [3]: x = x.set_index(['idx1', 'idx2', 'idx3']).sortlevel()

我的dataFrame:

In [4]: x
Out[4]:
                data
idx1 idx2 idx3
1    1    0        1
          1        1
          2        1
          3        1
          4        1
     2    0        1
          1        1
          2        1
          3        1
          4        1

首次使用loc:

In [5]: x.loc[1,:,:]
Out[5]:
           data
idx2 idx3
1    0        1
     1        1
     2        1
     3        1
     4        1
2    0        1
     1        1
     2        1
     3        1
     4        1

现在DataFrame只有两个索引:

In [6]: x
Out[6]:
           data
idx2 idx3
1    0        1
     1        1
     2        1
     3        1
     4        1
2    0        1
     1        1
     2        1
     3        1
     4        1

当'idx1'有多个值时,不会发生这种情况:

In [7]: x = pd.DataFrame({'idx1':[1]*3+[2]*7, 'idx2':[1]*5+[2]*5, 'idx3':range(5)+range(5), 'data': [1]*10})

In [8]: x = x.set_index(['idx1', 'idx2', 'idx3']).sortlevel()

In [9]: x
Out[9]:
                data
idx1 idx2 idx3
1    1    0        1
          1        1
          2        1
2    1    3        1
          4        1
     2    0        1
          1        1
          2        1
          3        1
          4        1

In [10]: x.loc[1,:,:]
Out[10]:
                data
idx1 idx2 idx3
1    1    0        1
          1        1
          2        1

In [11]: x
Out[11]:
                data
idx1 idx2 idx3
1    1    0        1
          1        1
          2        1
2    1    3        1
          4        1
     2    0        1
          1        1
          2        1
          3        1
          4        1

这是正常行为吗?怎么避免这个?

python 2.7 32bit,pandas == 0.16.2,numpy == 1.11.1 + mkl

1 个答案:

答案 0 :(得分:2)

我认为更好的是选择slicers,然后返回相同的输出 - 所有级别:

x = pd.DataFrame({'idx1':[1]*10, 'idx2':[1]*5+[2]*5, 'idx3':list(range(5))+list(range(5)), 'data': [1]*10})
x = x.set_index(['idx1', 'idx2', 'idx3']).sortlevel()
print (x)
                data
idx1 idx2 idx3      
1    1    0        1
          1        1
          2        1
          3        1
          4        1
     2    0        1
          1        1
          2        1
          3        1
          4        1

idx = pd.IndexSlice
print (x.loc[idx[1,:,:],:])
                data
idx1 idx2 idx3      
1    1    0        1
          1        1
          2        1
          3        1
          4        1
     2    0        1
          1        1
          2        1
          3        1
          4        1

如果需要删除级别,请使用带参数drop_level的{​​{3}}:

print (x.xs(1, level=0, drop_level=True))
           data
idx2 idx3      
1    0        1
     1        1
     2        1
     3        1
     4        1
2    0        1
     1        1
     2        1
     3        1
     4        1

print (x.xs(1, level=0, drop_level=False))
                data
idx1 idx2 idx3      
1    1    0        1
          1        1
          2        1
          3        1
          4        1
     2    0        1
          1        1
          2        1
          3        1
          4        1

第二个样本:

x = pd.DataFrame({'idx1':[1]*3+[2]*7, 'idx2':[1]*5+[2]*5, 'idx3':list(range(5))+list(range(5)), 'data': [1]*10})

x = x.set_index(['idx1', 'idx2', 'idx3']).sortlevel()
print (x)
                data
idx1 idx2 idx3      
1    1    0        1
          1        1
          2        1
2    1    3        1
          4        1
     2    0        1
          1        1
          2        1
          3        1
          4        1

idx = pd.IndexSlice
print (x.loc[idx[1,:,:],:])
                data
idx1 idx2 idx3      
1    1    0        1
          1        1
          2        1
print (x.xs(1, level=0, drop_level=True))
           data
idx2 idx3      
1    0        1
     1        1
     2        1

print (x.xs(1, level=0, drop_level=False))
                data
idx1 idx2 idx3      
1    1    0        1
          1        1
          2        1