Pandas在匹配多级索引水平上进行减法操作

8

我有一个带有两个多级索引的pandas数据帧

df
Out[202]: 
                     A         B         C         D
first second                                        
1     1      -0.080810  0.865259 -0.371148  0.346480
      2      -0.026636  1.259460 -1.109295 -0.871204
      3       0.372008 -1.778272  0.727838  0.620727
      4       0.918075  0.564741  2.027432 -1.614162
      5      -0.373527 -0.186027  0.225399  0.722733
2     1       0.344241  0.170596 -0.050763  2.692102
      2      -1.665413  0.357033 -0.691327 -0.983103
      3       1.277470 -1.841702  0.582107 -0.454315
      4       2.374108 -0.557879  0.797296  0.803622
      5      -1.001092  0.131217  0.131378 -0.636299  

我还有一个第二个数据框,由原始数据框中' second == 1 '多重索引级别的两行组成。

to_subtract = df.query('second == 1')  
to_subtract
Out[200]: 
                     A         B         C         D
first second                                        
1     1      -0.080810  0.865259 -0.371148  0.346480
2     1       0.344241  0.170596 -0.050763  2.692102

我想在第一级上将“df”减去“to_subtract”,但是对于与多级索引的第一级相对应的所有值。就如下面所示,Pandas知道如何基于匹配所有多级索引级别进行减法。

df.sub(to_subtract)
Out[201]: 
                A    B    C    D
first second                    
1     1       0.0  0.0  0.0  0.0
      2       NaN  NaN  NaN  NaN
      3       NaN  NaN  NaN  NaN
      4       NaN  NaN  NaN  NaN
      5       NaN  NaN  NaN  NaN
2     1       0.0  0.0  0.0  0.0
      2       NaN  NaN  NaN  NaN
      3       NaN  NaN  NaN  NaN
      4       NaN  NaN  NaN  NaN
      5       NaN  NaN  NaN  NaN

问题是,我该如何通过to_subtract [first == 1]减去df [first === 1]的所有值,并通过to_subtract [first == 2]减去df [first == 2]的所有值。我假设我可以使用for循环并遍历所有内容,但如果可能的话,我宁愿避免这样做,因为这些数据框在未来可能会变得更大。
提前感谢。
1个回答

4

我认为需要去掉MultiIndex的第二层,然后在DataFrame.sub中添加参数level=0以便按照第一层进行对齐:

to_subtract = df.query('second == 1').reset_index(level=1, drop=True)
#same as
#to_subtract = df.xs(1, level=1)
print (to_subtract)
              A         B         C         D
first                                        
1     -0.080810  0.865259 -0.371148  0.346480
2      0.344241  0.170596 -0.050763  2.692102

df1 = df.sub(to_subtract, level=0)
print (df1)
                     A         B         C         D
first second                                        
1     1       0.000000  0.000000  0.000000  0.000000
      2       0.054174  0.394201 -0.738147 -1.217684
      3       0.452818 -2.643531  1.098986  0.274247
      4       0.998885 -0.300518  2.398580 -1.960642
      5      -0.292717 -1.051286  0.596547  0.376253
2     1       0.000000  0.000000  0.000000  0.000000
      2      -2.009654  0.186437 -0.640564 -3.675205
      3       0.933229 -2.012298  0.632870 -3.146417
      4       2.029867 -0.728475  0.848059 -1.888480
      5      -1.345333 -0.039379  0.182141 -3.328401

没错!这个可行,谢谢你的帮助。顺便说一下,我注意到通过这样做,“to_subtract”失去了其中一个多级索引级别。出于好奇,有没有一种方法可以在不发生这种情况的情况下完成“to_subtract”? - Matt P.
@MattP. - 我认为不需要,可以保留它。 - jezrael
从pandas 1.4.2版本开始,df - to_subtractdf.sub(to_subtract)都可以正常工作,不再需要level=0。据我所知,这是因为pandas尽可能匹配尽可能多的共享索引级别。我不确定以前是否是这种情况;也许从来没有需要level=0。就我所看到的,真正的魔力在于df.xs(),它是一种超级优雅的按MultiIndex级别选择并删除该级别的方法,非常适合这种用例。 - Drew Levitt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接