代码之家  ›  专栏  ›  技术社区  ›  Cleb

如何在多索引数据帧中减去列?

  •  1
  • Cleb  · 技术社区  · 7 年前

    我有这样一个多索引数据帧:

    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', 'e', :] df_mult.loc['b', 'e', :] ,分别来自对应于 df_mult.loc['a', ['c', 'd'], :] df_mult.loc['b', ['c', 'd'], :]

                    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 .

    我该怎么做?

    2 回复  |  直到 7 年前
        1
  •  3
  •   MaxU - stand with Ukraine    7 年前

    更新2: 具有 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
    

    更新:

    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
    
        2
  •  2
  •   BENY    7 年前

    你在找这样的东西吗?( 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