2017-10-05 71 views
1

我有一个多指标数据帧是这样的:如何减去多索引数据帧中的列?

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 

我想要做的是从分别对应于df_mult.loc['a', ['c', 'd'], :]df_mult.loc['b', ['c', 'd'], :],值减去值df_mult.loc['a', 'e', :]df_mult.loc['b', 'e', :],分别。预期的结果将是

   val1 val2 
ind1 ind2 ind3    
a c 0  -6 -6 
      1  -6 -6 
      2  -6 -6 
    d 0  -3 -5 
      1  -3 -5 
      2  -3 -5 
    e 0  106 76 
      1  107 77 
      2  108 78 
b c 0  -6 -6 
      1  -6 -6 
      2  -6 -6 
    d 0  -3 -3 
      1  -3 -3 
      2  -3 -3 
    e 0  115 85 
      1  116 86 
      2  117 87 

理想的情况下,像这样的工作

df_mult.loc['a', ['c', 'd'], :].subtract(df_mult.loc['a', 'e', :]) 

但是这给了我很大的NaNs

我该怎么做?

+0

这是Python-2.x吗? –

+0

@WillemVanOnsem:是的。 – Cleb

回答

3

UPDATE2:kind help of @Divakar

def repeat_blocks(a, repeats=2, block_length=None): 
    N = a.shape[0] 
    if not block_length: 
     block_length = N//2 
    out = np.repeat(a.reshape(N//block_length,block_length,-1), 
        repeats, 
        axis=0) \ 
      .reshape(N*repeats,-1) 
    return out 

In [234]: df_mult.loc[idx[['a','b'], ['c', 'd'], :], :] -= repeat_blocks(df_mult.loc[['a','b'], 'e', :].values) 

In [235]: df_mult 
Out[235]: 
       val1 val2 
ind1 ind2 ind3 
a c 0  -6 -6 
      1  -6 -6 
      2  -6 -6 
    d 0  -3 -3 
      1  -3 -3 
      2  -3 -3 
    e 0  106 76 
      1  107 77 
      2  108 78 
b c 0  -6 -6 
      1  -6 -6 
      2  -6 -6 
    d 0  -3 -3 
      1  -3 -3 
      2  -3 -3 
    e 0  115 85 
      1  116 86 
      2  117 87 

UPDATE:

In [100]: idx = pd.IndexSlice 

In [102]: df_mult.loc[idx['a', ['c', 'd'], :], :] -= \ 
       np.concatenate([df_mult.loc['a', 'e', :].values] * 2) 

In [103]: df_mult 
Out[103]: 
       val1 val2 
ind1 ind2 ind3 
a c 0  -6 -6 
      1  -6 -6 
      2  -6 -6 
    d 0  -3 -3 
      1  -3 -3 
      2  -3 -3 
    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 

老(不正确)答案:

In [62]: df_mult.loc['a', 'e', :] -= df_mult.loc['b', 'e', :].values 

In [63]: df_mult 
Out[63]: 
       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  -9 -9 
      1  -9 -9 
      2  -9 -9 
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 
+0

感谢您的快速响应;我可能会错过一些东西,但这看起来不像预期的结果。 – Cleb

+0

我不太明白你想从什么减去什么... – MaxU

+0

对不起,不够精确。对于'ind1'中的每个值,我想从'ind2'中的所有剩余值中减去'e'(在'ind2'中)对应的所有值。例如。 '(a,c,0)= 100' - '(a,e,0)= 106'将会是'-6'(参见我在问题中期望的结果)。对于'(a,c,1)= 101','(a,e,1)= 107'也是'-6'等等。这是否更清晰? – Cleb

2

你在找什么东西吗? (df这里等于df_mult

idx = pd.IndexSlice 
df.loc[idx['a', ['c', 'd'], :],idx['val1','val2']]=df.loc['a', ['c', 'd'], :].values-np.tile(df.loc['a', 'e', :].values, (2, 1)) 

df 
Out[608]: 
       val1 val2 
ind1 ind2 ind3    
a c 0  -6 -6 
      1  -6 -6 
      2  -6 -6 
    d 0  -3 -3 
      1  -3 -3 
      2  -3 -3 
    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 
+0

是啊,我们已经在同一时间张贴;-) +1 – MaxU

+1

@MaxU感谢兄弟,我已经upvoted你的,当我看到你回答,我你展示解决问题的关键。 – Wen

+0

这似乎工作,谢谢(upvoted)!是否有一种简单的方法可以在'a'的'b'中执行相同的操作,还是需要遍历'ind1'中的所有元素?另外,有没有办法避免idx ['val1','val2']'因为我有很多列? – Cleb