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

解决pd.shift在缺失月份场景下无法匹配分类数据两个月前对应值的问题

嘿,我完全懂你的困扰!pd.shift()确实只关心行的位置顺序,不管实际日期差,一旦数据里有日期缺失(比如缺了某个月的记录),结果就完全不对了。咱们得换个思路——基于实际日期的匹配逻辑来实现需求,而不是单纯的行偏移。

先明确下两种常见的需求场景(因为你的预期结果和“两个月前”的描述有点小矛盾,我都列出来):


场景1:匹配「严格两个月前的日期」的col3值

如果你的需求是:对每条记录,找到同分类下日期正好是当前日期两个月前的col3值,不存在则显示NaN。

实现代码:

import pandas as pd
import numpy as np

# 加载你的数据(先转日期类型)
df = pd.DataFrame({
    'Col1': ['A', 'A', 'B', 'B'],
    'Col2': ['2020-01-08', '2020-01-11', '2020-01-06', '2020-01-08'],
    'col3': [25, 26, 32, 45]
})
df['Col2'] = pd.to_datetime(df['Col2'])

# 定义分组处理函数
def match_exact_two_month_ago(group):
    # 构建「日期→col3值」的映射字典
    date_to_value = group.set_index('Col2')['col3'].to_dict()
    # 计算每条记录的目标日期(当前日期减2个月)
    group['target_date'] = group['Col2'] - pd.DateOffset(months=2)
    # 匹配目标日期对应的col3值,无匹配则为NaN
    group['col4'] = group['target_date'].map(date_to_value)
    # 清理临时列
    return group.drop('target_date', axis=1)

# 按Col1分组处理
result = df.groupby('Col1').apply(match_exact_two_month_ago).reset_index(drop=True)
print(result)

输出结果:

Col1       Col2  col3  col4
0    A 2020-01-08    25   NaN
1    A 2020-01-11    26   NaN
2    B 2020-01-06    32   NaN
3    B 2020-01-08    45   NaN

(因为所有记录的两个月前日期都不在原始数据里,所以col4全是NaN,符合逻辑)


场景2:匹配「当前日期前、且间隔≤2个月的最近记录」的col3值

如果你的需求是:对每条记录,找到同分类下日期早于当前日期、且与当前日期差不超过2个月的最近一条记录的col3值,没有符合条件的则显示NaN(这更符合你给出的预期结果逻辑)。

实现代码:

import pandas as pd
import numpy as np

# 加载你给出的预期示例数据(包含新增的A-2020-01-10行)
df = pd.DataFrame({
    'Col1': ['A', 'A', 'A', 'B', 'B'],
    'Col2': ['2020-01-08', '2020-01-10', '2020-01-11', '2020-01-06', '2020-01-08'],
    'col3': [25, 56, 26, 32, 45]
})
df['Col2'] = pd.to_datetime(df['Col2'])

def match_recent_within_two_months(group):
    # 先按日期排序,确保顺序正确
    group_sorted = group.sort_values('Col2').reset_index(drop=True)
    # 计算每条记录与前一条记录的日期差
    group_sorted['date_diff'] = group_sorted['Col2'] - group_sorted['Col2'].shift(1)
    # 只有当日期差≤60天(约2个月)时,取前一条的col3值,否则为NaN
    group_sorted['col4'] = np.where(
        group_sorted['date_diff'] <= pd.Timedelta(days=60),
        group_sorted['col3'].shift(1),
        np.nan
    )
    # 清理临时列
    return group_sorted.drop('date_diff', axis=1)

# 分组处理
result = df.groupby('Col1').apply(match_recent_within_two_months).reset_index(drop=True)
print(result)

输出结果:

Col1       Col2  col3  col4
0    A 2020-01-08    25   NaN
1    A 2020-01-10    56  25.0
2    A 2020-01-11    26  56.0
3    B 2020-01-06    32   NaN
4    B 2020-01-08    45  32.0

这个结果和你给出的预期几乎一致,唯一的区别是A-2020-01-11的col4是56(因为它和前一条记录的日期差只有1天,符合≤2个月的条件),可能你的预期里这里是笔误?如果确实需要这条为NaN,可以再调整条件(比如只匹配正好两个月前或者其他规则)。


关键思路总结

  • 放弃单纯依赖行位置的shift(),转而基于日期计算+映射/条件判断来实现需求。
  • 用groupby()保证每个分类独立处理,避免跨分类匹配。
  • 可以通过pd.DateOffset()或pd.Timedelta()灵活定义时间间隔,适配不同的业务规则。

内容的提问来源于stack exchange,提问作者sayan_sen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.01 01:04:07