2017-10-05 56 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