问题描述
与未解决的 SO 问题 (Can one perform a left join in pandas that selects only the first match on the right?) 类似的问题,但稍微复杂一些,并且没有明显的解决方法。我希望可能会有一些新的功能或灵感可用。
我有两个数据框,我想从上到下以一对一的方式合并,而不是笛卡尔方式。例如:
l1=['a','b','c','c']
l2=['001','002','003','004']
l3=['a','a','c']
l4=['006','007','008','009','010','011','012','013']
dfa=pd.DataFrame(list(zip(l1,l2)),columns=['A1','A2'])
dfb=pd.DataFrame(list(zip(l3,l4)),columns=['B1','B2'])
dfa
Out[968]:
A1 A2
0 a 001
1 b 002
2 c 003
3 c 004
dfb
Out[969]:
B1 B2
0 a 006
1 a 007
2 b 008
3 b 009
4 c 010
5 c 011
6 c 012
7 c 013
在 A1 和 B1 列上“合并”后,我想要的结果是我只得到 4 行,每个 A1 / B1 值的第一个实例相互连接,每个 A1 / B1 的第二个实例价值相互加入,依此类推:-
A1 A2 B2
0 a 001 006
1 b 002 008
2 c 003 010
3 c 004 011
我不能左合并然后 groupby 并采用 first() / head(1),因为 A1 中的 c 不是唯一的。出于同样的原因,我也不能在 dfb 的 B1 上 drop_duplicates()。除此之外,除了一些复杂的使用循环之外,我没有想法。
有没有人有任何深刻的见解可以分享?
解决方法
让我们尝试使用 groupby()
+cumcount()
创建一个“键”列来跟踪位置,然后在 A1、B1 和键上合并:
dfa['key']=dfa.groupby(['A1']).cumcount()
dfb['key']=dfb.groupby(['B1']).cumcount()
df=dfa.merge(dfb,left_on=['A1','key'],right_on=['B1','key']).drop(['B1',1)
df
的输出:
A1 A2 B2
0 a 001 006
1 b 002 008
2 c 003 010
3 c 004 011
,
这是带有 assign
的版本。它真的和@Anurag Dabas 的版本一样工作
(dfa.assign(count=dfa.groupby('A1').transform('cumcount'))
.merge(dfb.assign(count=dfb.groupby('B1').transform('cumcount')),left_on=('A1','count'),right_on=('B1','count'))
).drop(['count','B1'],axis=1)