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

如何在Pandas DataFrame中按ID获取指定时间范围的滞后/前置值

解决方案:Pandas中按日期约束获取分组的滞后/前置测量值

可以实现,核心是利用日期范围筛选或merge_asof方法,替代无日期约束的shift()。针对你的需求,具体步骤如下:

1. 预处理日期列

首先确保所有日期列是datetime类型,避免格式错误:

import pandas as pd

# 假设你的数据集为df,包含字段:user_id, event_id, event_date, measure_date, measure_value
df['event_date'] = pd.to_datetime(df['event_date'])
df['measure_date'] = pd.to_datetime(df['measure_date'])

2. 方法一:用merge_asof高效匹配(推荐大数据量)

merge_asof支持按分组(user_id)和日期范围匹配最近的记录,完美解决shift()无日期约束的问题:

(1)获取事件前2个月内的最近测量值

# 拆分事件和测量数据(过滤空值干扰)
events = df.dropna(subset=['event_id']).sort_values(['user_id', 'event_date'])
measures = df.dropna(subset=['measure_value']).sort_values(['user_id', 'measure_date'])

# 匹配事件前2个月内的最近测量
prev_measures = pd.merge_asof(
    events,
    measures,
    by='user_id',  # 按用户分组匹配
    left_on='event_date',
    right_on='measure_date',
    direction='backward',  # 取小于等于事件日期的最近记录
    tolerance=pd.DateOffset(months=2)  # 限制在事件日期前2个月内
)
prev_measures = prev_measures.rename(columns={'measure_value': 'prev_measure'})

(2)获取事件后6个月内的最近测量值

next_measures = pd.merge_asof(
    events,
    measures,
    by='user_id',
    left_on='event_date',
    right_on='measure_date',
    direction='forward',  # 取大于等于事件日期的最近记录
    tolerance=pd.DateOffset(months=6)  # 限制在事件日期后6个月内
)
next_measures = next_measures.rename(columns={'measure_value': 'next_measure'})

(3)合并结果

final_df = pd.merge(
    prev_measures[['user_id', 'event_id', 'event_date', 'prev_measure']],
    next_measures[['user_id', 'event_id', 'event_date', 'next_measure']],
    on=['user_id', 'event_id', 'event_date'],
    how='left'
)

3. 方法二:分组后逐行筛选(直观,适合小数据量)

如果数据量不大,也可以通过分组后逐行筛选日期范围,取最近的测量值:

(1)定义获取前后测量值的函数

def get_prev_measure(row):
    # 筛选当前用户、事件日期前2个月内的测量记录
    user_measures = df[
        (df['user_id'] == row['user_id']) &
        (df['measure_date'] <= row['event_date']) &
        (df['measure_date'] >= row['event_date'] - pd.DateOffset(months=2))
    ]
    if not user_measures.empty:
        # 取日期最近的(即最大的measure_date对应的测量值)
        return user_measures.loc[user_measures['measure_date'].idxmax(), 'measure_value']
    return None

def get_next_measure(row):
    # 筛选当前用户、事件日期后6个月内的测量记录
    user_measures = df[
        (df['user_id'] == row['user_id']) &
        (df['measure_date'] >= row['event_date']) &
        (df['measure_date'] <= row['event_date'] + pd.DateOffset(months=6))
    ]
    if not user_measures.empty:
        # 取日期最近的(即最小的measure_date对应的测量值)
        return user_measures.loc[user_measures['measure_date'].idxmin(), 'measure_value']
    return None

(2)应用函数到每个事件

df['prev_measure'] = df.apply(get_prev_measure, axis=1)
df['next_measure'] = df.apply(get_next_measure, axis=1)

# 保留需要的字段
final_df = df.dropna(subset=['event_id'])[['user_id', 'event_id', 'event_date', 'prev_measure', 'next_measure']]

关键说明

  • merge_asof要求左右数据集必须按by和on的字段排序,效率远高于逐行apply,适合十万级以上数据。
  • 两种方法都会自动处理“无符合条件测量值”的情况,返回NaN,可根据需求填充默认值。

内容的提问来源于stack exchange,提问作者E. Camus

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 02:25:29