You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 20:31:06