如何基于前序预测与实际值关联填充Pandas DataFrame缺失值
基于实际值与预测值的差值规律填充Pandas缺失值
问题
如何基于已有前序行的商品预测值与另一列商品实际值的差值规律,填充Pandas DataFrame中的缺失值?
背景详情
我有一个10列40行的Pandas DataFrame,包含以下列:
Date:小时级时间戳;Actual:商品的实际观测值,无缺失;time_from_actual_1至time_from_actual_8:商品的超前预测值,仅每日首行(索引0、24)有初始值,其余23行均为NaN。
填充规则
要求time_from_actual_*列的缺失值遵循前一行预测值与实际值的差值保持恒定的规律,即:
当前行预测值 = 当前行实际值 + (前一行预测值 - 前一行实际值)
现有实现(嵌套循环)
我已通过嵌套for循环实现需求,但希望得到更高效、优雅的方案,以下是完整样本数据与代码:
# 导入库 import pandas as pd import numpy as np # 设置随机种子 np.random.seed(42) # 样本数据 data = { 'Date': pd.date_range(start='2023-01-01', periods=40, freq='H'), 'Actual': [100, 99.72, 101.02, 104.06, 103.60, 103.13, 106.29, 107.82, 106.88, 107.97, 107.04, 106.11, 106.59, 102.77, 99.32, 98.19, 96.17, 96.80, 94.98, 92.15, 95.09, 94.63, 94.77, 91.92, 90.83, 91.05, 88.75, 89.50, 88.30, 87.72, 86.51, 90.22, 90.19, 88.08, 89.72, 87.28, 87.70, 83.78, 81.12, 131.52], 'time_from_actual_1': [97] + [np.nan]*23 + [90] + [np.nan]*15, 'time_from_actual_2': [99] + [np.nan]*23 + [89] + [np.nan]*15, 'time_from_actual_3': [98] + [np.nan]*23 + [88] + [np.nan]*15, 'time_from_actual_4': [97] + [np.nan]*23 + [87] + [np.nan]*15, 'time_from_actual_5': [96] + [np.nan]*23 + [86] + [np.nan]*15, 'time_from_actual_6': [95] + [np.nan]*23 + [85] + [np.nan]*15, 'time_from_actual_7': [94] + [np.nan]*23 + [84] + [np.nan]*15, 'time_from_actual_8': [93] + [np.nan]*23 + [83] + [np.nan]*15, } # 创建DataFrame df = pd.DataFrame(data) # 复制原DataFrame用于参照原始缺失值 original_df = df.copy() # 获取所有预测列 time_cols = [col for col in df.columns if col.startswith('time_from_actual')] # 嵌套循环填充缺失值 for col in time_cols: for i in range(1, len(df)): if pd.isnull(df.loc[i, col]): j = i while j < len(df) and pd.isnull(original_df.loc[j, col]): previous_actual = df.loc[j - 1, 'Actual'] previous_time = df.loc[j - 1, col] current_actual = df.loc[j, 'Actual'] difference = previous_time - previous_actual df.loc[j, col] = current_actual + difference j += 1
优化方案:向量化操作实现
观察填充规则可以发现:预测值与实际值的差值在连续缺失段内是恒定的(即预测值 - 实际值 = 常数)。基于这个规律,我们可以用Pandas的向量化操作替代循环,大幅提升效率:
import pandas as pd import numpy as np np.random.seed(42) # 样本数据(同前) data = { 'Date': pd.date_range(start='2023-01-01', periods=40, freq='H'), 'Actual': [100, 99.72, 101.02, 104.06, 103.60, 103.13, 106.29, 107.82, 106.88, 107.97, 107.04, 106.11, 106.59, 102.77, 99.32, 98.19, 96.17, 96.80, 94.98, 92.15, 95.09, 94.63, 94.77, 91.92, 90.83, 91.05, 88.75, 89.50, 88.30, 87.72, 86.51, 90.22, 90.19, 88.08, 89.72, 87.28, 87.70, 83.78, 81.12, 131.52], 'time_from_actual_1': [97] + [np.nan]*23 + [90] + [np.nan]*15, 'time_from_actual_2': [99] + [np.nan]*23 + [89] + [np.nan]*15, 'time_from_actual_3': [98] + [np.nan]*23 + [88] + [np.nan]*15, 'time_from_actual_4': [97] + [np.nan]*23 + [87] + [np.nan]*15, 'time_from_actual_5': [96] + [np.nan]*23 + [86] + [np.nan]*15, 'time_from_actual_6': [95] + [np.nan]*23 + [85] + [np.nan]*15, 'time_from_actual_7': [94] + [np.nan]*23 + [84] + [np.nan]*15, 'time_from_actual_8': [93] + [np.nan]*23 + [83] + [np.nan]*15, } df = pd.DataFrame(data) # 获取所有预测列 time_cols = [col for col in df.columns if col.startswith('time_from_actual')] # 批量填充缺失值 for col in time_cols: # 计算预测值与实际值的差值 diff = df[col] - df['Actual'] # 向前填充差值(保持连续段内差值恒定) diff_filled = diff.ffill() # 反向计算得到填充后的预测值 df[col] = df['Actual'] + diff_filled
方案优势
- 效率提升:向量化操作避免了Python层循环,在大数据集下性能远超嵌套循环;
- 代码简洁:逻辑清晰直观,行数更少,易于维护和调试;
- 结果一致:完全符合原填充规则,输出结果与嵌套循环完全相同。
内容的提问来源于stack exchange,提问作者vestland
相关产品推荐
相关产品推荐

