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

基于前一行值计算Pandas列值时遇KeyError的解决方法

问题描述

现有包含多日期订单的DataFrame,需计算每个订单的实际完成时间,规则如下:

  • 若前一个订单的完成时间晚于当前订单的原始开始时间,则当前订单的实际开始时间更新为前一个订单的完成时间;
  • 计算需按日期分段,每日首个订单不依赖前一日最后一个订单的完成时间。

示例数据及DataFrame创建代码:

data = {'Date': ['2022-12-01', '2022-12-01', '2022-12-01', '2022-12-01', '2022-12-02', '2022-12-02', '2022-12-02', '2022-12-02'],
        'Order Start Time': ['2022-12-01 10:50:00.000', '2022-12-01 10:53:33.721', '2022-12-01 10:58:14.217', '2022-12-01 10:58:57.162', 
                             '2022-12-02 10:50:00.000', '2022-12-02 10:53:33.721', '2022-12-02 10:58:14.217', '2022-12-02 10:58:57.162'],
        'Order Rank Within Day': [1, 2, 3, 4, 1, 2, 3, 4],
        'Expected Completion Time': [125, 153, 75, 99, 165, 133, 85, 129]}

df = pd.DataFrame(data, columns=['Date', 'Order Start Time', 'Order Rank Within Day', 'Expected Completion Time'])

用户尝试的代码(运行出现KeyError):

for row in df.itertuples():
  df['completion_time'] = np.where(df['Order Rank Within Day']==1, pd.to_datetime(df['Order Start Time']) + pd.to_timedelta(df['Expected Completion Time'], unit='s'), df['completion_time'].at[row.Index-1])
问题分析
  1. 初始化错误:第一次循环时,row.Index为0,访问row.Index-1=-1,且completion_time列尚未创建,直接触发KeyError;
  2. 逻辑错误:np.where是整列批量操作,循环中每次覆盖整列,无法实现「当前订单依赖前一个订单结果」的递推计算;
  3. 分组缺失:未按Date分组,会导致跨日期订单互相影响,违反「每日独立计算」的需求。
解决方案

采用按日期分组+组内递推计算的方式,实现符合需求的逻辑:

步骤1:转换时间格式

先将Order Start Time转换为datetime类型,便于时间运算:

import pandas as pd

df['Order Start Time'] = pd.to_datetime(df['Order Start Time'])

步骤2:定义组内计算函数

针对每个日期的订单组,逐行递推计算实际开始时间和完成时间:

def calculate_daily_completion(group):
    # 确保组内按订单排序(示例已排序,此步为通用兼容)
    group = group.sort_values('Order Rank Within Day').reset_index(drop=True)
    # 初始化实际开始时间:首个订单用原始开始时间
    group['Actual Start Time'] = group['Order Start Time']
    
    # 从第二个订单开始递推
    for i in range(1, len(group)):
        # 获取前一个订单的完成时间
        prev_completion = group['Actual Start Time'].iloc[i-1] + pd.to_timedelta(group['Expected Completion Time'].iloc[i-1], unit='s')
        # 实际开始时间取「原始开始时间」和「前一个完成时间」的较大值
        group['Actual Start Time'].iloc[i] = max(group['Order Start Time'].iloc[i], prev_completion)
    
    # 计算实际完成时间
    group['Actual Completion Time'] = group['Actual Start Time'] + pd.to_timedelta(group['Expected Completion Time'], unit='s')
    return group

步骤3:分组应用函数

按Date分组后应用上述函数,得到最终结果:

df = df.groupby('Date').apply(calculate_daily_completion).reset_index(drop=True)

优化版(矢量化递推,避免显式循环)

如果订单量较大,可使用expanding结合apply实现矢量化递推,提升效率:

def vectorized_completion(group):
    group = group.sort_values('Order Rank Within Day').reset_index(drop=True)
    # 计算每个订单的理论完成时间(原始开始+时长)
    group['Theoretical Completion'] = group['Order Start Time'] + pd.to_timedelta(group['Expected Completion Time'], unit='s')
    
    # 递推计算实际完成时间:取当前理论完成时间和前一个实际完成时间的较大值
    group['Actual Completion Time'] = group['Theoretical Completion'].expanding().apply(
        lambda x: max(x.iloc[-1], x.iloc[-2]) if len(x)>=2 else x.iloc[0]
    )
    
    # 反推实际开始时间
    group['Actual Start Time'] = group['Actual Completion Time'] - pd.to_timedelta(group['Expected Completion Time'], unit='s')
    return group

df = df.groupby('Date').apply(vectorized_completion).reset_index(drop=True)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 23:40:19