pandas 对多级索引的部分连接

10 投票
1 回答
2544 浏览
提问于 2025-04-18 18:29

这是我遇到的问题:

dfa = pd.DataFrame({"a": [["a", "b", "c"][int(k/10)] for k in range(30)],
                    "b": ["a" + repr([10, 20, 30, 40, 50, 60][int(k/5)]) for k in range(30)],
                    "c": np.arange(30),
                    "d": np.random.normal(size=30)}).set_index(["a","b","c"])
dfb = pd.DataFrame({"a": [["a", "b", "c"][int(k/2)] for k in range(6)],
                    "b": ["a" + repr([10, 20, 30, 40, 50, 60][k]) for k in range(6)],
                    "m": np.random.normal(size=6)**2}).set_index(["a","b"])

简单来说,我有两个数据框(dataframe),它们都有多重索引。我想把 dfa.d 除以 dfb.m,并且是根据 ("a", "b") 这两个索引来连接的。不过,我不能直接用 dfa.d / dfb.m 或者用 join,因为系统提示说 在多重索引上合并多个层级的重叠尚未实现

我找到的最简单的方法是:

dfc = dfa.reset_index().set_index(["a", "b"]).join(dfb)
dfc["r"] = dfc.d / dfc.m
dfd = dfc.reset_index().set_index(["a", "b", "c"])[["r"]]

有没有什么快捷的方法呢?

1 个回答

5

这个问题有一个已知的bug,目前的进展版本是0.15.1

在更好的解决方案出现之前,可以按照以下步骤暂时解决这个问题:

  • 先把不匹配的索引层通过unstack变成列,先处理掉它们。
  • 然后进行乘法或除法运算。
  • 最后再用stack把列恢复到原来的样子。

具体操作如下:

In [109]: dfa.unstack('c').mul(dfb.squeeze(), axis=0).stack('c')
Out[109]: 
                  d
a b   c            
a a10 0    1.535221
      1   -2.151894
      2    1.986061
      3   -1.946031
      4   -4.868800
  a20 5   -2.278917
      6   -1.535684
      7    2.289102
      8   -0.442284
      9   -0.547209
b a30 10 -12.568426
      11   7.180348
      12   1.584510
      13   3.419332
      14  -3.011810
  a40 15  -0.367091
      16   4.264955
      17   2.410733
      18   0.030926
      19   1.219653
c a50 20   0.110586
      21  -0.430263
      22   0.350308
      23   1.101523
      24  -1.371180
  a60 25  -0.003683
      26   0.069884
      27   0.206635
      28   0.356708
      29   0.111380

注意两点:

  1. dfb必须是一个Series,否则在进行乘法时会有额外的麻烦,因为不清楚要用dfb的哪一列。你可以把dfb.squeeze()换成dfb['m']
  2. 如果不匹配的索引不是三个中的最后一个,那么索引层的顺序就会被打乱。在这种情况下,可以按照@jreback的建议,在之后重新排序索引层:.reorder_levels(dfa.index.names)

撰写回答