在Pandas中将级别添加到DF的中间位置

时间:2017-02-27 13:32:22

标签: python pandas

我想在我的DF中添加一个新级别(这样我就可以使用pd.reindex来做其他事情)。我的DF基本上有这样的东西:

df = pd.DataFrame({('A','a'): [-1,-1,0,10,12],
                   ('A','b'): [0,1,2,3,-1],
                   ('A','c'): [-1,1,0,10,12],
                   ('A','d'): [1,1,2,3,-1],
                   ('B','a'): [-20,-10,0,10,20],
                   ('B','b'): [-200,-100,0,-1,200],
                   ('B','c'): [-20,-10,0,10,20],
                   ('B','d'): [-200,-100,0,100,200]
})

##df
    A               B
    a   b   c   d   a   b     c     d
0   -1  0   1   1   -20 -200  -20   -200
1   -1  1   -1  1   -10 -100  -10   -100
2   0   2   0   2   0   0     0     0
3   10  3   10  3   10  -1    10    100
4   12  -1  12  -1  20  200   20    200

我想分配新的关卡L1 = a + bL2 = c + d。我该怎么做?

所需的输出是

##df
    A               B
    L1      L2      L1        L2
    a   b   c   d   a   b     c     d
0   -1  0   1   1   -20 -200  -20   -200
1   -1  1   -1  1   -10 -100  -10   -100
2   0   2   0   2   0   0     0     0
3   10  3   10  3   10  -1    10    100
4   12  -1  12  -1  20  200   20    200

编辑:目标是为了实现类似here中提到的内容。这意味着某些行对于相同的KEY将具有NA s,具体取决于其他列的值。 例如。如果我想通过分别测试列ac是否为负数来过滤列bd

##df
    A               B
    L1      L2      L1        L2
    a   b   c   d   a   b     c     d
0   -1  0   1   1   NA  NA    NA    NA
1   -1  1   -1  1   NA  NA    NA    NA
2   0   2   0   2   0   0     0     0
3   10  3   10  3   NA  NA    10    100
4   NA  NA  NA  NA  20  200   20    200

1 个答案:

答案 0 :(得分:3)

您需要使用array创建新的map,然后指定:

d = {'a':'L1','b':'L1','c':'L2','d':'L2'}
a = df.columns.get_level_values(1).map(lambda x: d[x])
print (a)
['L1' 'L1' 'L2' 'L2' 'L1' 'L1' 'L2' 'L2']

df.columns = [df.columns.get_level_values(0),a,df.columns.get_level_values(1)]
#same as
df.columns = pd.MultiIndex.from_arrays([df.columns.get_level_values(0),
                                        df.columns.get_level_values(1).map(lambda x: d[x]),
                                        df.columns.get_level_values(1)])
print (df)
    A             B              
   L1     L2     L1       L2     
    a  b   c  d   a    b   c    d
0  -1  0  -1  1 -20 -200 -20 -200
1  -1  1   1  1 -10 -100 -10 -100
2   0  2   0  2   0    0   0    0
3  10  3  10  3  10   -1  10  100
4  12 -1  12 -1  20  200  20  200

第二个输出真的很复杂,对我而言:

#filter columns
idx = pd.IndexSlice
mask = df.loc[:, idx[:,:,['b','d']]] < 0
print (mask)
       A             B       
      L1     L2     L1     L2
       b      d      b      d
0  False  False   True   True
1  False  False   True   True
2  False  False  False  False
3  False  False   True  False
4   True   True  False  False

#create mask to columns a,c
mask1 = mask.reindex(columns=df.columns)
mask1 = mask1.groupby(level=[0,1], axis=1).apply(lambda x: x.bfill(axis=1))
print (mask1)
       A                           B                     
      L1            L2            L1            L2       
       a      b      c      d      a      b      c      d
0  False  False  False  False   True   True   True   True
1  False  False  False  False   True   True   True   True
2  False  False  False  False  False  False  False  False
3  False  False  False  False   True   True  False  False
4   True   True   True   True  False  False  False  False

print (df.mask(mask1))
      A                     B                    
     L1         L2         L1           L2       
      a    b     c    d     a      b     c      d
0  -1.0  0.0  -1.0  1.0   NaN    NaN   NaN    NaN
1  -1.0  1.0   1.0  1.0   NaN    NaN   NaN    NaN
2   0.0  2.0   0.0  2.0   0.0    0.0   0.0    0.0
3  10.0  3.0  10.0  3.0   NaN    NaN  10.0  100.0
4   NaN  NaN   NaN  NaN  20.0  200.0  20.0  200.0

使用reindexmethod='bfill'的另一个解决方案,但是必须进行双重转置(我认为它是错误的 - 仅适用于MultiIndex中的index,而不适用于{{1在MultiIndex):

columns