Diebold-Mariano 检验 Python 实战:3步完成模型预测精度显著性对比
Diebold-Mariano 检验 Python 实战3步完成模型预测精度显著性对比在时间序列预测项目中我们常常需要比较不同模型的预测效果。比如ARIMA和LSTM模型在同一数据集上的表现孰优孰劣仅仅观察平均误差的差异可能不够严谨——这差异是真实的模型能力体现还是数据采样带来的偶然结果Diebold-Mariano检验简称DM检验正是为解决这一问题而生。本文将带你从零实现DM检验的Python代码并通过完整案例演示如何在实际项目中应用。无论你是数据分析师还是算法工程师都能快速掌握这套方法论为模型选择提供统计显著性依据。1. DM检验核心原理与Python函数封装DM检验的核心思想是通过统计检验判断两个模型的预测误差差异是否显著。其零假设是两个模型的预测精度相同若检验结果拒绝该假设则说明一个模型显著优于另一个。关键计算步骤计算损失差分序列对于两个模型的预测误差序列e1和e2长度均为T计算每个时间点的损失差分d [e1[i] - e2[i] for i in range(T)] # 假设使用MSE损失计算统计量DM统计量服从标准正态分布计算公式为import numpy as np d_mean np.mean(d) d_std np.std(d, ddof1) # 样本标准差 DM d_mean / (d_std / np.sqrt(T))结果解读查标准正态分布表得到p-valuefrom scipy import stats p_value 2 * (1 - stats.norm.cdf(abs(DM))) # 双侧检验完整Python函数实现def dm_test(e1, e2, loss_funcmse, h1, power2): Diebold-Mariano检验实现 参数: e1, e2: 两个模型的预测误差序列(长度相同) loss_func: 损失函数类型(mse, mae或自定义函数) h: 预测步长(用于调整自相关) power: 损失函数的幂次(当loss_funcmse时自动设为2) 返回: DM统计量, p-value assert len(e1) len(e2), 误差序列长度必须相同 T len(e1) # 计算损失差分 if loss_func mse: d [e1[i]**2 - e2[i]**2 for i in range(T)] elif loss_func mae: d [abs(e1[i]) - abs(e2[i]) for i in range(T)] else: d [loss_func(e1[i]) - loss_func(e2[i]) for i in range(T)] # 计算DM统计量(考虑自相关) d_mean np.mean(d) gamma [np.mean([(d[k] - d_mean) * (d[k - lag] - d_mean) for k in range(lag, T)]) for lag in range(1, h)] var_d np.var(d, ddof1) 2 * sum(gamma) DM d_mean / np.sqrt(var_d / T) # 计算p-value p_value 2 * (1 - stats.norm.cdf(abs(DM))) return DM, p_value提示实际应用中预测误差可能存在自相关特别是多步预测时。上述实现通过参数h考虑了这一点使用Newey-West方差估计器进行修正。2. 端到端应用案例ARIMA vs LSTM模型比较让我们通过一个完整案例演示DM检验的实际应用。假设我们有一个月度销售数据集分别用ARIMA和LSTM模型进行预测现在要比较两者的预测精度。数据准备与模型训练import pandas as pd from statsmodels.tsa.arima.model import ARIMA from tensorflow.keras.models import Sequential from tensorflow.keras.layers import LSTM, Dense # 加载数据 data pd.read_csv(sales.csv, parse_dates[date], index_coldate) train data.iloc[:-24] # 前N-24个月训练 test data.iloc[-24:] # 最后24个月测试 # ARIMA模型 arima ARIMA(train, order(1,1,1)).fit() arima_pred arima.forecast(24) # LSTM模型准备 def create_dataset(dataset, look_back1): X, Y [], [] for i in range(len(dataset)-look_back): X.append(dataset[i:(ilook_back)]) Y.append(dataset[ilook_back]) return np.array(X), np.array(Y) look_back 3 train_X, train_Y create_dataset(train.values, look_back) test_X, test_Y create_dataset(test.values, look_back) # LSTM模型训练 model Sequential() model.add(LSTM(50, input_shape(look_back, 1))) model.add(Dense(1)) model.compile(lossmean_squared_error, optimizeradam) model.fit(train_X, train_Y, epochs100, batch_size1, verbose0) lstm_pred model.predict(test_X)计算预测误差并执行DM检验# 计算预测误差 arima_errors test.values.flatten() - arima_pred lstm_errors test_Y.flatten() - lstm_pred.flatten() # 执行DM检验 dm_stat, p_value dm_test(arima_errors, lstm_errors, loss_funcmse) print(fDM统计量: {dm_stat:.4f}) print(fP-value: {p_value:.4f}) if p_value 0.05: if dm_stat 0: print(结论: ARIMA预测显著优于LSTM (p 0.05)) else: print(结论: LSTM预测显著优于ARIMA (p 0.05)) else: print(结论: 两个模型预测精度无显著差异)结果可视化分析import matplotlib.pyplot as plt plt.figure(figsize(12, 6)) plt.plot(test.index, test.values, label实际值, colorblack) plt.plot(test.index, arima_pred, labelARIMA预测, linestyle--) plt.plot(test.index[look_back:], lstm_pred, labelLSTM预测, linestyle:) plt.title(模型预测效果对比) plt.legend() plt.show() # 绘制误差分布 plt.figure(figsize(10, 5)) plt.boxplot([arima_errors, lstm_errors], labels[ARIMA误差, LSTM误差]) plt.title(预测误差分布对比) plt.show()3. 高级应用与注意事项3.1 不同损失函数的选择DM检验支持多种损失函数常见选择包括损失函数公式适用场景MSEe²强调大误差惩罚MAEeMAPEe/y# 使用MAE损失的DM检验 dm_mae, p_mae dm_test(arima_errors, lstm_errors, loss_funcmae) # 自定义损失函数示例 def huber_loss(e, delta1.0): return np.where(np.abs(e) delta, 0.5*e**2, delta*(np.abs(e)-0.5*delta)) dm_huber, p_huber dm_test(arima_errors, lstm_errors, loss_funchuber_loss)3.2 多步预测的调整当进行h步预测时误差通常呈现MA(h-1)自相关结构。这时需要设置合适的h参数使用Newey-West方差估计考虑小样本修正HLN检验# 12步超前预测的DM检验 dm_multi, p_multi dm_test(arima_errors, lstm_errors, h12) # HLN修正(小样本更准确) def hln_test(dm_stat, h, T): return dm_stat / np.sqrt((T 1 - 2*h h*(h-1)/T) / T) hln_stat hln_test(dm_multi, h12, Tlen(arima_errors)) hln_p 2 * (1 - stats.norm.cdf(abs(hln_stat)))3.3 常见问题解决方案问题1检验结果与误差均值矛盾可能原因误差分布不对称或存在极端值解决方案尝试不同损失函数或检查误差分布问题2p值边界显著如0.04-0.06建议增加测试集样本量或使用交叉验证多次检验问题3多重检验问题当比较多个模型时需要进行p值校正from statsmodels.stats.multitest import multipletests pvals [0.03, 0.05, 0.01] # 假设三个比较的p值 reject, adj_pvals, _, _ multipletests(pvals, methodholm)4. 工程实践中的优化技巧在实际项目中我们可以进一步优化DM检验的实现4.1 自动化检验流程def auto_dm_test(model_dict, test_data, loss_funcs[mse, mae]): 自动化多模型比较 model_dict: {模型名称: 预测值}的字典 test_data: 真实值 loss_funcs: 使用的损失函数列表 results [] models list(model_dict.keys()) for i in range(len(models)): for j in range(i1, len(models)): e1 test_data - model_dict[models[i]] e2 test_data - model_dict[models[j]] for loss in loss_funcs: dm, p dm_test(e1, e2, loss_funcloss) results.append({ model1: models[i], model2: models[j], loss_func: loss, DM_stat: dm, p_value: p, significance: p 0.05 }) return pd.DataFrame(results)4.2 结合交叉验证from sklearn.model_selection import TimeSeriesSplit def cv_dm_test(model1, model2, data, n_splits5): 交叉验证版DM检验 tscv TimeSeriesSplit(n_splitsn_splits) p_values [] for train_idx, test_idx in tscv.split(data): train, test data[train_idx], data[test_idx] # 训练模型并预测(此处简化实际需适配具体模型) pred1 model1.fit(train).predict(test) pred2 model2.fit(train).predict(test) _, p dm_test(test-pred1, test-pred2) p_values.append(p) # 组合各折p值(Fisher方法) combined_stat -2 * sum(np.log(p_values)) combined_p 1 - stats.chi2.cdf(combined_stat, df2*n_splits) return combined_p4.3 性能优化建议对于大规模时间序列可以使用numpy向量化计算对长序列采用滚动窗口检验并行化多模型比较# 向量化实现示例 def dm_test_vectorized(e1, e2, h1): d e1**2 - e2**2 # MSE d_mean np.mean(d) lags np.arange(1, h) gamma [np.sum((d[lag:] - d_mean) * (d[:-lag] - d_mean)) / len(d) for lag in lags] var_d np.var(d, ddof1) 2 * sum(gamma) DM d_mean / np.sqrt(var_d / len(d)) p 2 * (1 - stats.norm.cdf(abs(DM))) return DM, p在实际项目中我曾遇到一个有趣案例当比较Prophet和XGBoost在销售预测中的表现时DM检验结果随预测周期长度变化而反转。短期1-3天XGBoost显著更优但长期7天以上Prophet反而更好。这提醒我们模型比较需要放在具体应用场景下评估。

相关新闻

Mac Mouse Fix终极指南:让普通鼠标在macOS上超越苹果触控板的5个专业技巧

Mac Mouse Fix终极指南:让普通鼠标在macOS上超越苹果触控板的5个专业技巧

Mac Mouse Fix终极指南:让普通鼠标在macOS上超越苹果触控板的5个专业技巧 【免费下载链接】mac-mouse-fix Mac Mouse Fix - Make Your $10 Mouse Better Than an Apple Trackpad! 项目地址: https://gitcode.com/GitHub_Trending/ma/mac-mouse-fix Mac Mouse…

2026/7/5 12:07:09阅读更多 →
Scanpy 1.10 单细胞质控实战:3指标联合过滤与Scrublet双细胞识别(附Python代码)

Scanpy 1.10 单细胞质控实战:3指标联合过滤与Scrublet双细胞识别(附Python代码)

Scanpy 1.10 单细胞质控实战:3指标联合过滤与Scrublet双细胞识别(附Python代码)1. 单细胞RNA测序质控的核心逻辑单细胞RNA测序(scRNA-seq)数据的质量控制(QC)是分析流程中至关重要的第一步。与bulk RNA-seq不同,单细胞数据具有更高…

2026/7/5 12:07:09阅读更多 →
集成学习实战:Bagging/Boosting/Stacking

集成学习实战:Bagging/Boosting/Stacking

集成学习实战:Bagging/Boosting/Stacking 1. 集成学习原理 集成学习(Ensemble Learning): ├── 核心思想:多个弱学习器组合成强学习器 ├── 三大方法: │ ├── Bagging:并行训练&#x…

2026/7/5 12:02:09阅读更多 →
PCB湿制程/PCB设备定制/PCB水平线设备/PCB水平蚀刻生产线公司国内优选

PCB湿制程/PCB设备定制/PCB水平线设备/PCB水平蚀刻生产线公司国内优选

本文旨在梳理2026年国内PCB设备相关市场的主流品质公司,分析行业发展动态与竞争特色。PCB设备作为电子信息产业重要的生产基础支撑,其性能直接关联线路板生产效率、产品精度与制造质量,对整个电子产业链的升级发展有着重要影响。随着国内电子…

2026/7/5 13:07:27阅读更多 →
程序员就业:换个角度,把工具链跑成稳定流程

程序员就业:换个角度,把工具链跑成稳定流程

如果你正准备往大模型方向转,《程序员就业:2026 年还能靠什么拿到,从问题拆解到交付验证》这类问题别只看热度。更重要的是判断自己该补哪块能力,以及怎么证明你真的会。摘要这篇面向准备找工作、跳槽或转型的程序员,但…

2026/7/5 13:07:27阅读更多 →
中小学课桌椅/报告厅座椅/大学教室桌椅/校园课桌椅/高校阶梯教室排椅公司优选

中小学课桌椅/报告厅座椅/大学教室桌椅/校园课桌椅/高校阶梯教室排椅公司优选

本文旨在梳理2026年中国校园公共家具市场的主流品质公司,分析行业发展动态与竞争特色。校园公共家具作为教育教学开展的重要基础配套,其品质直接关联师生健康安全、使用体验及教育空间提质升级。随着国家对校园建设标准的不断提升与消费者对教育场景品质…

2026/7/5 13:07:27阅读更多 →
蝶阀/不锈钢阀门/化工阀门/沪工阀门厂家优选指南

蝶阀/不锈钢阀门/化工阀门/沪工阀门厂家优选指南

本文旨在梳理2026年国内闸阀蝶阀不锈钢阀门化工阀门沪工阀门市场的主流品质企业,分析行业发展动态与竞争特色。阀门作为市政给排水、消防工程、化工生产、暖通系统的核心基础部件,其品质直接关联工程运行安全、生产效率及公共服务稳定性。随着国内基建投…

2026/7/5 13:07:27阅读更多 →
提升开发效率的五个Python工具推荐

提升开发效率的五个Python工具推荐

你的时间不应该浪费在重复劳动上作为一名写过十年代码的开发者,我越来越清楚地意识到:真正决定开发效率的,不是你的打字速度,也不是你背下了多少API,而是你选择使用哪些工具。那些每天只花半小时部署环境、五分钟定位b…

2026/7/5 13:07:27阅读更多 →
Scala类与对象:从Java思维到工程契约的范式跃迁

Scala类与对象:从Java思维到工程契约的范式跃迁

1. 为什么 Scala 的类与对象不是“Java 换个名字”那么简单?你刚接触 Scala,看到class Car和new Car(),第一反应可能是:“哦,和 Java 差不多嘛”。我试过——在带第一个 Scala 小组做电商后台时,也是这么想…

2026/7/5 13:02:27阅读更多 →
从GitHub安全案例解析常见漏洞与防护实践

从GitHub安全案例解析常见漏洞与防护实践

1. 项目概述:从GitHub Trending看安全实战 最近在GitHub Trending上看到一个项目,叫 skills4/skills ,它因为一些安全漏洞案例被大家讨论。这其实是一个挺典型的场景:一个旨在展示或教授某种技能的仓库,本身却成了安…

2026/7/5 0:01:08阅读更多 →
MLT 2026启示:因果推理与概率建模驱动下一代LLM应用

MLT 2026启示:因果推理与概率建模驱动下一代LLM应用

# MLT 2026启示:因果推理与概率建模驱动下一代LLM应用## 一、背景与挑战:从“黑箱预测”到“可信推理”2026年6月,第7届机器学习与趋势国际会议(MLT 2026)将在悉尼召开。会议议程中,“因果与可解释机器学习…

2026/7/5 0:01:08阅读更多 →
通达OA SQL注入漏洞深度剖析:从手工注入到自动化利用与防御

通达OA SQL注入漏洞深度剖析:从手工注入到自动化利用与防御

1. 项目概述与漏洞背景最近在梳理一些历史OA系统的安全风险时,通达OA v11.6版本中的一个老漏洞又进入了我的视线。这个漏洞位于/general/bi_design/appcenter/report_bi.func.php文件中,是一个典型的SQL注入点。虽然这个漏洞的利用方式看起来并不复杂&am…

2026/7/5 0:01:08阅读更多 →
从GitHub安全案例解析常见漏洞与防护实践

从GitHub安全案例解析常见漏洞与防护实践

1. 项目概述:从GitHub Trending看安全实战 最近在GitHub Trending上看到一个项目,叫 skills4/skills ,它因为一些安全漏洞案例被大家讨论。这其实是一个挺典型的场景:一个旨在展示或教授某种技能的仓库,本身却成了安…

2026/7/5 0:01:08阅读更多 →
MLT 2026启示:因果推理与概率建模驱动下一代LLM应用

MLT 2026启示:因果推理与概率建模驱动下一代LLM应用

# MLT 2026启示:因果推理与概率建模驱动下一代LLM应用## 一、背景与挑战:从“黑箱预测”到“可信推理”2026年6月,第7届机器学习与趋势国际会议(MLT 2026)将在悉尼召开。会议议程中,“因果与可解释机器学习…

2026/7/5 0:01:08阅读更多 →
通达OA SQL注入漏洞深度剖析:从手工注入到自动化利用与防御

通达OA SQL注入漏洞深度剖析:从手工注入到自动化利用与防御

1. 项目概述与漏洞背景最近在梳理一些历史OA系统的安全风险时,通达OA v11.6版本中的一个老漏洞又进入了我的视线。这个漏洞位于/general/bi_design/appcenter/report_bi.func.php文件中,是一个典型的SQL注入点。虽然这个漏洞的利用方式看起来并不复杂&am…

2026/7/5 0:01:08阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/5 1:30:27阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/5 3:48:10阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/5 3:48:09阅读更多 →