如何基于Ticker与非精确匹配的Date连接两个DataFrame,缺失对应日期时取后续最近日期的Price值?
Pandas实现按Ticker+Date匹配,无精确值时取后续最近日期的Price
这个需求用pandas的merge_asof函数就能完美解决,它专门设计用来处理这种需要基于键值找最近匹配的连接场景,完全符合你要的“精确匹配优先,无匹配则取同Ticker下后续最近日期”的逻辑。
具体实现步骤
首先,我们先还原你的数据并完成必要的预处理,再执行连接操作:
import pandas as pd # 构建DataFrame-A(营收数据) df_a = pd.DataFrame({ 'Ticker': ['AAPL', 'AAPL', 'MSFT', 'MSFT'], 'Date': ['2022-01-01', '2022-04-01', '2022-01-01', '2022-04-01'], 'Renue': ['10M', '10M', '10M', '10M'] }) # 构建DataFrame-B(价格数据) df_b = pd.DataFrame({ 'Ticker': ['AAPL', 'AAPL', 'AAPL', 'AAPL', 'MSFT', 'MSFT', 'MSFT', 'MSFT', 'MSFT'], 'Date': ['2022-01-02', '2022-01-03', '2022-04-01', '2022-04-02', '2022-01-01', '2022-01-02', '2022-01-03', '2022-04-02', '2022-04-03'], 'Price': [11, 12, 15, 16, 20, 21, 22, 26, 26] }) # 关键步骤:将Date列转换为datetime类型,否则无法正确进行日期比较 df_a['Date'] = pd.to_datetime(df_a['Date']) df_b['Date'] = pd.to_datetime(df_b['Date']) # merge_asof要求右侧DataFrame必须按连接键排序,所以先对df_b按Ticker和Date排序 df_b_sorted = df_b.sort_values(by=['Ticker', 'Date']) # 执行核心的连接操作 result = pd.merge_asof( df_a, df_b_sorted, on='Date', # 基于Date列做匹配 by='Ticker', # 按Ticker分组,只在同一只股票的范围内找日期 direction='forward' # 找**大于等于**当前Date的最近日期,精确匹配优先,无匹配则取后续最近 ) print(result)
代码解释
- 日期类型转换:必须把字符串格式的日期转成
datetime类型,否则字符串的比较逻辑和日期逻辑不一致,会导致匹配错误。 - 排序右侧DataFrame:
merge_asof要求右侧的DataFrame必须按on(Date)和by(Ticker)的列排序,这样才能高效找到最近的匹配项。 - merge_asof参数说明:
by='Ticker':确保我们只在同一个股票代码的数据集里找对应的日期,不会出现AAPL的日期匹配到MSFT的价格这种错误。direction='forward':这是实现需求的核心参数,它会为df_a中的每个日期,在df_b的同Ticker下寻找第一个大于等于该日期的记录——如果有精确匹配的日期,就直接取对应Price;如果没有,就取之后最近的日期的Price,完全符合你的要求。
运行结果
执行代码后得到的结果和你预期的完全一致:
| Ticker | Date | Renue | Price |
|---|---|---|---|
| AAPL | 2022-01-01 | 10M | 11 |
| AAPL | 2022-04-01 | 10M | 15 |
| MSFT | 2022-01-01 | 10M | 20 |
| MSFT | 2022-04-01 | 10M | 26 |
额外注意事项
- 如果df_b中某个Ticker下没有比df_a中日期晚的记录,
merge_asof会给该条的Price赋值为NaN,你可以根据需求用fillna()处理或者删除这些行。 - 确保两个DataFrame的Ticker列格式一致(比如都是字符串、大小写统一),否则分组匹配会出错。
内容的提问来源于stack exchange,提问作者Alan Kam
相关产品推荐
相关产品推荐

