4. 缺失值插补策略对比与选择
任务与数据设定
本节使用一段逐小时 PM2.5 序列(示例数据,共 72 小时),人为挖去 12 个点模拟缺失,并保留一个邻近站点 B 的同步序列作为回归插补的自变量。三种策略在同一缺失掩码下比较:前向填充(ffill)、线性插值(按时间索引线性)、邻近站点回归(用 B 站浓度对 A 站做线性回归后预测缺失点)。
评估方式采用人工挖洞交叉验证:从完整段中随机再挖 12 个已知点作为验证集,用三种策略分别插补后计算 RMSE 与 MAE。这样误差是在真实值上算出来的,而不是在插补值上自证。
实现代码
import numpy as np
import pandas as pd
from sklearn.linear_model import LinearRegression
rng = np.random.default_rng(42)
hours = pd.date_range("2024-03-01", periods=72, freq="h")
# 示例数据:A 站真实浓度(含日变化 + 噪声),B 站为相关序列
base = 45 + 18 * np.sin(np.arange(72) * 2 * np.pi / 24)
a_true = base + rng.normal(0, 4, 72)
b_station = 0.85 * a_true + 6 + rng.normal(0, 3, 72)
df = pd.DataFrame({"time": hours, "A": a_true, "B": b_station}).set_index("time")
# 1) 制造缺失:12 个缺失点 + 12 个验证点(验证点先记录真值再挖掉)
miss_idx = rng.choice(72, 12, replace=False)
remain = np.setdiff1d(np.arange(72), miss_idx)
val_idx = rng.choice(remain, 12, replace=False)
df["A_missing"] = df["A"].copy()
df.loc[df.index[miss_idx], "A_missing"] = np.nan
val_truth = df["A"].iloc[val_idx].copy()
df_cv = df["A_missing"].copy()
df_cv.iloc[val_idx] = np.nan # 验证点也挖掉,供交叉验证
# 2) 前向填充
ffill = df_cv.ffill()
# 3) 线性插值(按时间索引)
linear = df_cv.interpolate(method="time")
# 4) 邻近站点回归:用非缺失且非验证点训练
train_mask = df_cv.notna()
reg = LinearRegression().fit(
df.loc[train_mask, ["B"]], df.loc[train_mask, "A_missing"]
)
reg_pred = pd.Series(np.nan, index=df.index)
reg_pred[~train_mask] = reg.predict(df.loc[~train_mask, ["B"]])
# 5) 在验证点上比较
def score(pred):
p = pred.iloc[val_idx]
rmse = np.sqrt(np.mean((p - val_truth) ** 2))
mae = np.mean(np.abs(p - val_truth))
return round(rmse, 2), round(mae, 2)
results = pd.DataFrame({
"策略": ["前向填充", "线性插值", "邻近站点回归"],
"RMSE": [score(ffill)[0], score(linear)[0], score(reg_pred)[0]],
"MAE": [score(ffill)[1], score(linear)[1], score(reg_pred)[1]],
})
print(results)
print("回归系数:", reg.coef_, "截距:", reg.intercept_)
结果判读与选择依据
示例运行会得到类似下表的结果(数值随随机种子固定,属示例输出):
| 策略 | RMSE | MAE | 适用条件 |
|---|---|---|---|
| 前向填充 | 约 9–12 | 约 7–9 | 缺失连续且短、序列变化平缓;会引入阶梯状偏差 |
| 线性插值 | 约 5–7 | 约 4–6 | 缺失为孤立点、时间间隔均匀;对长段缺失会拉直线 |
| 邻近站点回归 | 约 3–5 | 约 2–4 | 存在强相关邻近站点且同步性好;需保证训练点不含缺失 |
选择依据不是“误差最小就选它”,而要结合三点:①缺失形态——孤立点优先线性插值,连续长段优先回归或标记不插补;②可用协变量——有同步邻近站点且相关系数高(如 r>0.8)时回归更稳;③下游用途——若用于超标统计,插补值不应系统性偏低,需检查插补后均值与完整段均值的偏差。
回归插补必须只用非缺失、非验证的样本训练,否则验证点信息泄漏会让误差虚低。若邻近站点本身也有缺失,需先对齐时间索引再训练。
快速执行清单
- 先记录验证点真值,再从序列中挖掉,避免信息泄漏。
- 回归插补的训练集只取非缺失、非验证样本。
- 比较 RMSE 与 MAE 之外,额外检查插补后序列均值与完整段均值的偏差。
- 连续长段缺失(如超过 6 小时)不建议纯插值,应保留缺失标记并在统计时说明。