【问题标题】:How to subtract columns in a multiindex dataframe?如何减去多索引数据框中的列?
【发布时间】:2017-10-05 19:48:38
【问题描述】:

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

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

我该怎么做?

【问题讨论】:

  • 这是 Python-2.x 吗?
  • @WillemVanOnsem:是的。

标签: python pandas dataframe subtraction


【解决方案1】:

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

更新:

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

【讨论】:

  • 感谢您的快速回复;我可能会错过一些东西,但这看起来不像是预期的结果。
  • 抱歉不够精确。对于ind1 中的每个值,我想从ind2 中的所有剩余值中减去与eind2 中)对应的所有值。例如。 (a, c, 0)=100 - (a, e, 0)=106 将是 -6 (请参阅问题中我想要的结果)。然后 (a, c, 1)=101 - (a, e, 1)=107 也是 -6 等等。是不是更清楚了?
  • 看起来不错,确实(赞成)。是否有一种简单的方法可以在 a 中对 b 执行相同操作,或者我是否必须遍历 ind1 中的所有元素?
  • 更新 2 为 b3 而不是 -6)和 a-12 不正确)给出了错误的结果。
【解决方案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

【讨论】:

  • 是的,我们同时发布了 ;-) +1
  • @MaxU 谢谢老兄,我已经为你投票了,当我看到你回答时,我展示了解决问题的关键。
  • 这似乎有效,谢谢(赞成)!是否有一种简单的方法可以在 a 中对 b 执行相同操作,或者我是否必须遍历 ind1 中的所有元素?另外,有没有办法避免idx['val1','val2'],因为我有很多列?
  • @Cleb,到目前为止,我只能提供for循环方法,比如for x,df in df.groupby('ind1'):
  • @Wen:是的,这就是我对这两个答案都投赞成票的原因;但如果有办法避免循环,那就更好了:)
猜你喜欢
  • 2019-03-08
  • 1970-01-01
  • 1970-01-01
  • 2021-04-26
  • 2018-06-29
  • 1970-01-01
  • 2020-12-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多