pandas 对多级索引的部分连接
这是我遇到的问题:
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
注意两点:
dfb
必须是一个Series
,否则在进行乘法时会有额外的麻烦,因为不清楚要用dfb
的哪一列。你可以把dfb.squeeze()
换成dfb['m']
。- 如果不匹配的索引不是三个中的最后一个,那么索引层的顺序就会被打乱。在这种情况下,可以按照@jreback的建议,在之后重新排序索引层:
.reorder_levels(dfa.index.names)