我知道这是一个老问题,但对于新手来说,现在有pandas.merge_asof函数可以执行基于最接近匹配的连接。
如果您想要进行合并,以便将一个DataFrame (df_right
) 的一列放置在另一个DataFrame (df_left
) 的两列之间,则可以执行以下操作:
df_left = pd.DataFrame({
"time_from": [1, 4, 10, 21],
"time_to": [3, 7, 15, 27]
})
df_right = pd.DataFrame({
"time": [2, 6, 16, 25]
})
df_left
time_from time_to
0 1 3
1 4 7
2 10 15
3 21 27
df_right
time
0 2
1 6
2 16
3 25
首先,找到最接近但比左侧DataFrame的左边界(time_from
)更大的正确DataFrame的匹配项:
merged = pd.merge_asof(
left=df_1,
right=df_2.rename(columns={"time": "candidate_match_1"}),
left_on="time_from",
right_on="candidate_match_1",
direction="forward"
)
merged
time_from time_to candidate_match_1
0 1 3 2
1 4 7 6
2 10 15 16
3 21 27 25
正如您所看到的,索引2中的候选匹配是错误的,因为16不在10和15之间。
然后,在右DataFrame中查找最接近但小于左DataFrame右边界(time_to
)的匹配项:
merged = pd.merge_asof(
left=merged,
right=df_2.rename(columns={"time": "candidate_match_2"}),
left_on="time_to",
right_on="candidate_match_2",
direction="backward"
)
merged
time_from time_to candidate_match_1 candidate_match_2
0 1 3 2 2
1 4 7 6 6
2 10 15 16 6
3 21 27 25 25
最后,保留候选匹配相同的匹配项,这意味着右侧DataFrame的值在左侧DataFrame的2列值之间:
merged["match"] = None
merged.loc[merged["candidate_match_1"] == merged["candidate_match_2"], "match"] = \
merged.loc[merged["candidate_match_1"] == merged["candidate_match_2"], "candidate_match_1"]
merged
time_from time_to candidate_match_1 candidate_match_2 match
0 1 3 2 2 2
1 4 7 6 6 6
2 10 15 16 6 None
3 21 27 25 25 25
merge
函数不接受任何函数参数的事实表明可能没有优雅的解决方案。但我对pandas了解甚少,所以希望有专家能够出现并证明相反的观点 :) - Andras Deak -- Слава Україні