如何用Pandas按时间距离实现正负数据的一对一匹配
问题描述
需要将数据中正stem(数值为正的条目)匹配到时间上最近的负stem(数值为负的条目),匹配规则如下:
- 匹配核心依据为两者的时间距离,取正stem时间点之前最近的负stem
- 每个负stem仅能被匹配一次,匹配完成后不可再用于其他正stem
- 若正stem与目标负stem的时间差≥自定义阈值X,则不参与匹配
示例:正stem A匹配负stem B;负stem B已被占用,无法再匹配正stem C;负stem D与A、C的时间差过大,不参与匹配。
对应的DataFrame如下:
import pandas as pd df = pd.DataFrame({ 'BOX_187_084_11': [-190.379230, -261.853410, 268.353538, 258.084186], 'label': ['D', 'B', 'A', 'C'] }, index=pd.to_datetime(['2005-12-01', '2008-03-01', '2008-09-01', '2011-09-01']))
Pandas风格解决方案
利用Pandas的merge_asof工具结合去重逻辑,可简洁实现需求,步骤如下:
分离正负stem数据集
将原数据拆分为正、负stem两个子集,并重置索引保留时间列:pos_df = df[df['BOX_187_084_11'] > 0].reset_index().rename(columns={'index': 'pos_time'}) neg_df = df[df['BOX_187_084_11'] < 0].reset_index().rename(columns={'index': 'neg_time'})按时间匹配最近负stem
使用merge_asof按时间正序匹配,设置时间差阈值X(示例设为3年),仅匹配正stem之前最近的负stem:X = pd.Timedelta(days=3*365) # 自定义时间差阈值 matched = pd.merge_asof( pos_df.sort_values('pos_time'), neg_df.sort_values('neg_time'), left_on='pos_time', right_on='neg_time', direction='backward', # 匹配时间更早的最近负stem tolerance=X )确保负stem唯一匹配
对匹配结果按负stem去重,保留每个负stem对应的最早正stem匹配:final_matched = matched.drop_duplicates(subset='neg_time', keep='first')整理可视化结果
重命名列名,输出直观的匹配结果:result = final_matched[['pos_time', 'label_x', 'neg_time', 'label_y', 'BOX_187_084_11_x', 'BOX_187_084_11_y']] result.columns = ['正stem时间', '正stem标签', '负stem时间', '负stem标签', '正stem数值', '负stem数值'] print(result)
输出结果
运行后会得到符合规则的匹配结果:
| 正stem时间 | 正stem标签 | 负stem时间 | 负stem标签 | 正stem数值 | 负stem数值 |
|---|---|---|---|---|---|
| 2008-09-01 | A | 2008-03-01 | B | 268.353538 | -261.853410 |
正stem C与最近的负stem B时间差超过3年,且无其他符合条件的负stem,因此不被匹配;负stem D因时间差过大也未参与匹配。
内容的提问来源于stack exchange,提问作者Dante van der Heijden
相关产品推荐
相关产品推荐

