如何基于pandas DataFrame另一列的日期条件获取指定列值
pandas按日期偏移逐行取对应值实现方案
问题背景
现有结构化DataFrame如下:
A B Start_Date 1 4 2003-05-22 2 6 2003-05-31 .... 57 406 2018-09-08
需求为逐行计算:取所有日期≤当前行Start_Date + 10年的记录中,最后一条记录对应的B列值,存入新列D,预期输出结构:
A B Start_Date D 1 4 2003-05-22 <2013-05-22及之前最后一条记录的B值> 2 6 2003-05-31 <2013-05-31及之前最后一条记录的B值> .... 57 406 2018-09-08 <2028-09-08及之前最后一条记录的B值>
之前尝试的代码仅返回B列全局最大值,不符合逐行匹配要求。
前置准备
所有日期相关操作前,必须先将日期列转为pandas的datetime格式,否则会出现日期比较、计算错误:
import pandas as pd df['Start_Date'] = pd.to_datetime(df['Start_Date'])
注意:计算10年偏移请用pd.DateOffset(years=10),按自然年计算,不会出现平闰年、大小月导致的日期偏差,不要直接用pd.Timedelta(days=365*10)做偏移
实现方案
方案1:直观逐行实现(适合10万行以内小数据集)
逻辑简单直接,不需要提前排序,逐行筛选符合日期条件的记录取最后一个B值:
# 生成每行的10年截止日期辅助列 df['cutoff_date'] = df['Start_Date'] + pd.DateOffset(years=10) # 逐行匹配取值 df['D'] = df.apply( lambda row: df.loc[df['Start_Date'] <= row['cutoff_date'], 'B'].iloc[-1], axis=1 ) # 可选:删除辅助列 df.drop(columns=['cutoff_date'], inplace=True)
该方案缺点是逐行遍历全表做筛选,数据量超过20万行时运行速度会明显变慢。
方案2:merge_asof高效实现(推荐大数据量场景,速度提升数十倍)
如果数据本身按Start_Date升序排列(样例数据从2003年到2018年符合该特征),用pandas原生的时序最近匹配函数merge_asof实现,全表向量化运算,效率极高:
# 生成截止日期辅助列 df['cutoff_date'] = df['Start_Date'] + pd.DateOffset(years=10) # 构造匹配用的日期-B值对照表 lookup_table = df[['Start_Date', 'B']].rename(columns={'B': 'D'}) # 按截止日期做向后匹配,自动找小于等于截止日期的最后一条对应B值 df = pd.merge_asof( df.sort_values('cutoff_date'), lookup_table.sort_values('Start_Date'), left_on='cutoff_date', right_on='Start_Date', direction='backward' ) # 清理多余列、还原列名 df.drop(columns=['cutoff_date', 'Start_Date_y'], inplace=True) df.rename(columns={'Start_Date_x': 'Start_Date'}, inplace=True)
原代码错误原因
之前编写的代码存在两个核心问题:
- 条件判断直接用整列做广播比较,没有限定逐行的匹配范围,筛选结果几乎覆盖全表
- 末尾调用
.max()是对筛选后的整个B列求全局最大值,没有做逐行取值逻辑,因此只会返回整个B列的最大数。
内容的提问来源于stack exchange,提问作者Gopal Sharma
相关产品推荐
相关产品推荐

