如何为DataFrame按ID匹配最近上下日期并添加列?
解决方案
要高效实现需求,我们可以利用pandas.merge_asof()的direction参数分别处理「最近更小日期」和「最近更大日期」,无需手动循环或复杂操作。具体步骤如下:
步骤1:转换日期格式
首先将字符串类型的日期转为datetime类型,确保能正确比较大小:
import pandas as pd df1 = pd.DataFrame({'ID':['A', 'A', 'B', 'B'], 'Date':['31.08.2023', '12.09.2023', '13.09.2023', '20.08.2023']}) df2 = pd.DataFrame({'ID':['A', 'A', 'A', 'B', 'B'], 'Date':['30.08.2023', '14.09.2023', '10.09.2023', '28.09.2023', '19.08.2023']}) # 转换为datetime(注意dayfirst=True适配DD.MM.YYYY格式) df1['Date'] = pd.to_datetime(df1['Date'], dayfirst=True) df2['Date'] = pd.to_datetime(df2['Date'], dayfirst=True)
步骤2:用merge_asof分别匹配上下日期
merge_asof()要求左右表按匹配键排序,我们先对两个表按ID和Date排序,再通过direction参数区分匹配规则:
direction='backward':匹配同ID下小于等于当前日期的最近日期(对应DATE_DOWN)direction='forward':匹配同ID下大于等于当前日期的最近日期(对应DATE_UP)
# 对两个表按ID和Date排序,满足merge_asof的要求 df1_sorted = df1.sort_values(['ID', 'Date']) df2_sorted = df2.sort_values(['ID', 'Date']) # 匹配DATE_DOWN:最近的更小/相等日期 df_down = pd.merge_asof(df1_sorted, df2_sorted, on='Date', by='ID', direction='backward') df_down = df_down.rename(columns={'Date_y': 'DATE_DOWN'}) # 匹配DATE_UP:最近的更大/相等日期 df_up = pd.merge_asof(df1_sorted, df2_sorted, on='Date', by='ID', direction='forward') df_up = df_up.rename(columns={'Date_y': 'DATE_UP'})
步骤3:合并结果并恢复原格式
将两个匹配结果合并,恢复原数据的索引顺序,并把日期转回原字符串格式:
# 合并结果,保留原df1的索引顺序 final_df = pd.merge(df_down[['ID', 'Date_x', 'DATE_DOWN']], df_up[['ID', 'Date_x', 'DATE_UP']], on=['ID', 'Date_x']) final_df = final_df.set_index(df1.index).sort_index() # 转回DD.MM.YYYY格式的字符串 final_df = final_df.rename(columns={'Date_x': 'DATE'}) final_df['DATE'] = final_df['DATE'].dt.strftime('%d.%m.%Y') final_df['DATE_UP'] = final_df['DATE_UP'].dt.strftime('%d.%m.%Y') final_df['DATE_DOWN'] = final_df['DATE_DOWN'].dt.strftime('%d.%m.%Y') print(final_df)
执行后输出结果与需求完全一致:
ID DATE DATE_UP DATE_DOWN 0 A 31.08.2023 10.09.2023 30.08.2023 1 A 12.09.2023 14.09.2023 10.09.2023 2 B 13.09.2023 28.09.2023 19.08.2023 3 B 20.08.2023 28.09.2023 19.08.2023
为什么这个方法高效?
merge_asof()底层基于排序后的二分查找实现,时间复杂度为O(n log n),属于向量化操作,远快于逐行循环或apply的方式,适合处理大规模数据。
内容的提问来源于stack exchange,提问作者Aleksandra
相关产品推荐
相关产品推荐

