news 2026/10/9 23:36:57

2025五一赛B题矿山数据处理:从预处理到建模的完整链路与避坑指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
2025五一赛B题矿山数据处理:从预处理到建模的完整链路与避坑指南

简介:本资源为2025年五一数学建模竞赛B题「矿山监测数据的高效处理与建模优化研究」的完整参赛作品,包含完整论文与配套代码,面向具备一定数学建模基础、关注矿山监测数据处理的科研人员与工程师。作品综合运用BP神经网络、主成分分析、卡尔曼滤波与贝叶斯优化等方法,围绕数据拟合、降维压缩、去噪建模、超参数自适应调整及高维数据重构五个问题给出完整求解方案,测试集拟合优度最高达0.9870。资源包共1个PDF文件,大小约3.23MB,内容涵盖问题背景重述、模型假设、各问题分析与求解过程、误差检验及算法复杂度讨论,结构完整、逻辑清晰。目前已有306人学习下载,博主自述为个人参赛作品,保底二等奖水平,适合作为数学建模竞赛的参考范例,也可为金融、气象、交通等领域的时序数据处理提供迁移思路。

1. 矿山数据处理赛题的底层逻辑:为什么它成了2025年五一赛B题的硬骨头

2025年五一赛B题把场景放在矿山,表面看是道数学建模题,实际是一道披着行业外衣的数据处理综合题。矿山数据有几个绕不开的特点:传感器多、采样频率不统一、缺失值和异常值混在一起、量纲差异大,还经常出现时间戳对不齐的情况。很多队伍拿到题第一反应是套预测模型,结果在数据清洗阶段就翻车了。这道题真正考的是你能不能把脏数据变成可建模的干净矩阵,再用合理的模型给出可解释的结论。适合谁看?准备参加数学建模竞赛的学生、刚接触工业时序数据的工程师、以及想补上"数据预处理到建模"这条链路的人。下面我按自己带队的实际路径,把这道题从读题到出论文的完整流程拆开讲。

2. 矿山数据预处理:从原始表格到可建模矩阵的完整链路

矿山数据处理的第一个分水岭就在预处理。我见过太多队伍直接把原始Excel丢进模型,最后结果惨不忍睹。这一章把预处理拆成缺失值处理、异常值检测、多源对齐三个环节,每个环节给出可复现的代码和参数选择理由。

2.1 缺失值的三类处理策略与选择依据

矿山传感器数据缺失通常分三种:随机缺失、连续块缺失、整列缺失。随机缺失用插值,连续块缺失要判断是否设备停机,整列缺失直接考虑剔除该特征。我一般先用pandas做缺失分布统计,再决定策略。

import pandas as pd import numpy as np # 读取原始矿山数据,假设第一列是时间戳 df = pd.read_csv('mine_data.csv', parse_dates=['timestamp']) df = df.set_index('timestamp').sort_index() # 统计每列缺失率和最大连续缺失长度 def missing_profile(series): mask = series.isna() missing_rate = mask.mean() # 计算最大连续缺失长度 groups = (~mask).cumsum() max_consecutive = mask.groupby(groups).sum().max() if mask.any() else 0 return pd.Series({'missing_rate': missing_rate, 'max_consecutive': max_consecutive}) profile = df.apply(missing_profile) print(profile.sort_values('missing_rate', ascending=False))

这段代码输出每列的缺失率和最大连续缺失长度。判断规则:缺失率超过40%且最大连续缺失超过50个采样点的列,直接剔除;缺失率在10%到40%之间的列,用线性插值加前后向填充组合;缺失率低于10%的列,用三次样条插值。参数上,max_consecutive的阈值我一般设50,对应高频传感器约10分钟的停机,超过这个长度插值就是编数据了。

2.2 异常值检测:3σ和IQR到底该用哪个

异常值检测没有万能方法。矿山数据里,振动传感器适合IQR,因为分布偏态;温度压力类适合3σ,接近正态。我的做法是两条路都跑,取交集作为高置信异常,取并集作为疑似异常。

from scipy import stats def detect_outliers(series, method='both'): clean = series.dropna() # 3σ方法 z = np.abs(stats.zscore(clean)) sigma_out = clean.index[z > 3] # IQR方法 q1, q3 = clean.quantile([0.25, 0.75]) iqr = q3 - q1 lower, upper = q1 - 1.5 * iqr, q3 + 1.5 * iqr iqr_out = clean.index[(clean < lower) | (clean > upper)] if method == 'both': high_conf = sigma_out.intersection(iqr_out) suspect = sigma_out.union(iqr_out) return high_conf, suspect return sigma_out if method == 'sigma' else iqr_out # 对每个数值列检测 for col in df.select_dtypes(include=[np.number]).columns: high, suspect = detect_outliers(df[col]) print(f"{col}: 高置信异常{len(high)}个, 疑似异常{len(suspect)}个")

高置信异常直接置为NaN走插值,疑似异常保留但打标记,在后续建模时作为特征输入。这样做的理由是矿山数据里有些"异常"其实是真实工况突变,直接删会丢信息。参数上,3σ的阈值可以放宽到3.5,IQR的1.5倍可以调到2.0,取决于你对数据质量的容忍度。

2.3 多源时间对齐:重采样与滑动窗口的配合

矿山数据来自不同设备,采样频率从1秒到1小时不等。对齐的核心是统一到同一个时间网格。我一般选中间频率作为基准,比如1分钟,高频降采样用均值,低频升采样用插值。

# 统一重采样到1分钟 df_resampled = df.resample('1min').agg({ 'vibration': 'mean', # 高频振动取均值 'temperature': 'mean', 'pressure': 'mean', 'production': 'sum' # 产量类累加 }) # 对重采样后仍缺失的做插值 df_resampled = df_resampled.interpolate(method='time', limit=5) # 构建滑动窗口特征,窗口大小60,步长1 def make_windows(data, window=60, step=1): windows = [] for i in range(0, len(data) - window, step): windows.append(data.iloc[i:i+window].values) return np.array(windows) feature_cols = ['vibration', 'temperature', 'pressure'] X = make_windows(df_resampled[feature_cols]) print(f"窗口数据形状: {X.shape}")

重采样时聚合函数的选择很关键:振动、温度、压力用均值,产量、能耗用求和,状态标志用众数或最后一个值。插值的limit=5表示连续缺失超过5个点就不插了,避免过度平滑。滑动窗口的60对应1小时历史,这个参数要根据预测目标调整,预测未来10分钟用60,预测未来1小时用180。

3. 特征工程与模型选型:让矿山数据开口说话

预处理完只是拿到干净数据,真正决定论文质量的是特征工程和模型选择。这一章讲怎么从时序数据里挖出有物理意义的特征,以及为什么这道题我推荐树模型加时序模型的组合。

3.1 时域特征与频域特征的提取清单

矿山数据的特征分三类:统计特征、时域特征、频域特征。统计特征就是均值方差那些,时域特征包括过零率、峰值因子,频域特征靠FFT。我一般提取以下清单:

特征类型具体特征计算方式适用场景
统计特征均值、标准差、偏度、峰度pandas内置所有数值列
时域特征均方根、峰值因子、裕度因子自定义函数振动信号
频域特征主频、频谱熵、频带能量FFT后计算振动、电流
趋势特征滑动斜率、差分均值线性回归温度、压力
from scipy.fft import fft from scipy.stats import skew, kurtosis def extract_features(window_data, fs=1.0): """window_data: (window_size, n_features)""" feats = [] for i in range(window_data.shape[1]): sig = window_data[:, i] # 统计特征 feats.extend([np.mean(sig), np.std(sig), skew(sig), kurtosis(sig)]) # 时域特征 rms = np.sqrt(np.mean(sig**2)) peak = np.max(np.abs(sig)) crest = peak / (rms + 1e-8) feats.extend([rms, peak, crest]) # 频域特征 spectrum = np.abs(fft(sig))[:len(sig)//2] freqs = np.fft.fftfreq(len(sig), 1/fs)[:len(sig)//2] dominant_freq = freqs[np.argmax(spectrum)] spectral_entropy = -np.sum((spectrum/spectrum.sum()) * np.log(spectrum/spectrum.sum() + 1e-8)) feats.extend([dominant_freq, spectral_entropy]) return np.array(feats) # 对每个窗口提取特征 feature_matrix = np.array([extract_features(w) for w in X]) print(f"特征矩阵形状: {feature_matrix.shape}")

每个窗口提取的特征维度是n_features * 9,三个传感器就是27维。频域特征里主频和频谱熵对设备故障最敏感,峰值因子对冲击类异常敏感。注意FFT之前要去均值,否则直流分量会干扰主频判断。

3.2 树模型与时序模型的组合策略

这道题的目标通常是预测某个指标或做异常分类。我的经验是:如果目标列和特征之间是非线性关系且特征维度高,用XGBoost或LightGBM;如果目标有明显时序依赖,用LSTM或GRU;最稳的方案是两者做 stacking。

import lightgbm as lgb from sklearn.model_selection import TimeSeriesSplit from sklearn.metrics import mean_squared_error # 时间序列交叉验证,不能随机打乱 tscv = TimeSeriesSplit(n_splits=5) params = { 'objective': 'regression', 'metric': 'rmse', 'num_leaves': 31, 'learning_rate': 0.05, 'feature_fraction': 0.8, 'bagging_fraction': 0.8, 'bagging_freq': 5, 'verbose': -1 } scores = [] for train_idx, val_idx in tscv.split(feature_matrix): X_train, X_val = feature_matrix[train_idx], feature_matrix[val_idx] y_train, y_val = y[train_idx], y[val_idx] dtrain = lgb.Dataset(X_train, y_train) dval = lgb.Dataset(X_val, y_val, reference=dtrain) model = lgb.train(params, dtrain, num_boost_round=500, valid_sets=[dval], callbacks=[lgb.early_stopping(50)]) pred = model.predict(X_val, num_iteration=model.best_iteration) scores.append(np.sqrt(mean_squared_error(y_val, pred))) print(f"CV RMSE: {np.mean(scores):.4f} ± {np.std(scores):.4f}")

参数上,num_leaves控制在31到63之间,太大容易过拟合;learning_rate用0.05配合early_stopping;feature_fraction和bagging_fraction都设0.8增加鲁棒性。时间序列交叉验证必须用TimeSeriesSplit,随机KFold会泄露未来信息,这是很多人翻车的地方。

3.3 模型融合:加权平均还是Stacking

单模型调好后,融合能再涨一两个点。简单加权平均适合模型差异大的情况,Stacking适合模型互补性强的情况。我一般先试加权,不行再上Stacking。

from sklearn.linear_model import Ridge from sklearn.ensemble import RandomForestRegressor # 基模型 lgb_model = lgb.train(params, lgb.Dataset(feature_matrix, y), num_boost_round=300) rf_model = RandomForestRegressor(n_estimators=200, max_depth=10, random_state=42) rf_model.fit(feature_matrix, y) # 加权平均,权重通过验证集搜索 best_w, best_score = 0, float('inf') for w in np.arange(0, 1.05, 0.05): blend = w * lgb_model.predict(feature_matrix) + (1-w) * rf_model.predict(feature_matrix) score = np.sqrt(mean_squared_error(y, blend)) if score < best_score: best_score, best_w = score, w print(f"最优权重: LGB={best_w:.2f}, RF={1-best_w:.2f}, RMSE={best_score:.4f}")

加权平均的权重搜索粒度0.05就够了,再细容易过拟合验证集。Stacking的话用Ridge做元学习器,把基模型的预测作为输入,注意元学习器的训练数据要用交叉验证的折外预测,否则还是会泄露。

4. 论文写作与代码组织:让评委一眼看到你的工作量

建模竞赛的论文不是技术文档,评委看的是逻辑清晰、图表规范、结论有支撑。这一章讲论文结构怎么搭、代码怎么组织才能既复现又好看。

4.1 论文五段式结构与图表规范

我带的队伍论文统一用这个结构:问题重述与分析、数据预处理、模型建立与求解、结果分析与检验、模型评价与推广。每部分的比例大概是1:2:3:2:1,模型部分是重头。

图表规范上,所有图必须带标题、坐标轴标签、单位。折线图用不同线型区分,不要只靠颜色。表格用三线表,参数表要标注取值范围和选择理由。我一般要求论文里至少包含:数据缺失分布图、异常值检测图、特征重要性排序图、预测结果对比图、误差分布图。这五张图能把工作量直观展示出来。

import matplotlib.pyplot as plt plt.rcParams['font.sans-serif'] = ['SimHei'] plt.rcParams['axes.unicode_minus'] = False fig, axes = plt.subplots(2, 2, figsize=(12, 10)) # 缺失分布 df.isna().mean().plot(kind='bar', ax=axes[0,0], title='各列缺失率') # 异常值 axes[0,1].plot(df.index, df['vibration'], label='原始') axes[0,1].scatter(high_conf_idx, df.loc[high_conf_idx, 'vibration'], c='red', label='高置信异常', s=10) axes[0,1].legend(); axes[0,1].set_title('振动异常检测') # 特征重要性 lgb.plot_importance(model, ax=axes[1,0], max_num_features=15) # 预测对比 axes[1,1].plot(y_val[:200], label='真实') axes[1,1].plot(pred[:200], label='预测') axes[1,1].legend(); axes[1,1].set_title('预测对比') plt.tight_layout() plt.savefig('paper_figures.png', dpi=300)

出图用300dpi,字体统一SimHei,负号要设置axes.unicode_minus=False否则显示方块。特征重要性图用LightGBM内置的plot_importance,比手动画省事。

4.2 代码目录结构与复现说明

代码目录我一般这样组织:data/放原始数据,src/放脚本,output/放结果,figures/放图。主脚本按01_preprocess、02_features、03_train、04_evaluate编号,保证执行顺序清晰。

project/ ├── data/ │ ├── raw/ │ └── processed/ ├── src/ │ ├── 01_preprocess.py │ ├── 02_features.py │ ├── 03_train.py │ └── 04_evaluate.py ├── output/ │ ├── models/ │ └── results/ ├── figures/ └── README.md

README里写清楚运行环境、依赖安装、执行顺序。依赖用requirements.txt固定版本,避免评委环境不一致跑不通。我一般会加一个run_all.sh一键执行,但注意路径要用相对路径,别写死绝对路径。

5. 避坑指南:矿山数据处理赛题里最容易翻车的五个地方

这一章是我带队和看别人论文总结的血泪经验,每条都按现象、原因、解决来写。

坑一:用随机KFold做交叉验证。现象是验证集RMSE很低但测试集一塌糊涂。原因是时序数据有自相关性,随机划分会让未来信息泄露到训练集。解决是改用TimeSeriesSplit,并且特征工程里的滑动窗口不能跨折计算。

坑二:缺失值插值后不做标记。现象是模型在插值段预测偏差大。原因是插值数据是编的,模型无法区分真实值和插值。解决是加一列缺失标记,插值位置标1,其余标0,作为特征输入。

坑三:异常值直接删除。现象是数据量骤减,模型欠拟合。原因是矿山数据的异常往往是真实工况,删了就丢信息。解决是高置信异常置NaN走插值,疑似异常保留并打标记。

坑四:特征不做归一化就喂给树模型。现象是树模型对某些特征不敏感。原因是树模型虽然对量纲不敏感,但特征重要性会被量纲大的特征主导。解决是统一做标准化,或者用基于排序的特征重要性。

坑五:论文里只放最终结果不放中间过程。现象是评委觉得工作量不够。原因是只展示了模型精度,没展示数据清洗和特征工程的过程。解决是把缺失分布、异常检测、特征重要性这些中间图都放进论文,让评委看到完整链路。

6. 从赛题到落地:矿山数据处理方案的复用与进阶

这道题做完,方案本身可以复用到很多工业时序场景。我一般会把预处理和特征工程部分封装成模块,换个数据集就能跑。进阶方向有三个:一是引入自动化特征工程工具,比如tsfresh,能自动提取几百个时序特征再筛选;二是用深度学习模型做端到端,比如TCN或Transformer,省去手工特征但需要更多数据;三是做在线推理,把训练好的模型部署成API,实时接收传感器数据做预测。

验证方案是否靠谱,我习惯做两件事:一是用不同时间段的数据做回测,看模型在时间上的稳定性;二是做特征消融实验,逐个去掉特征看性能下降多少,下降多的就是核心特征。这两个动作能让论文的结论更有说服力。

# 特征消融示例 base_score = np.sqrt(mean_squared_error(y_val, model.predict(X_val))) importance = model.feature_importance(importance_type='gain') sorted_idx = np.argsort(importance)[::-1] for i in sorted_idx[:10]: X_ablated = X_val.copy() X_ablated[:, i] = 0 ablated_score = np.sqrt(mean_squared_error(y_val, model.predict(X_ablated))) print(f"去掉特征{i}: RMSE上升{ablated_score - base_score:.4f}")

消融实验里,RMSE上升最多的特征就是最关键的。这个结果可以直接写进论文的模型分析部分,比单纯列特征重要性更有说服力。

最后说个我自己的习惯:每次做完题,我会把踩过的坑和对应的解决代码整理成一个checklist,下次遇到类似赛题先过一遍。这个习惯让我从第一次参赛的翻车到现在能稳定出活。矿山数据处理这道题,难点不在模型多复杂,而在数据链路每一步都别偷懒。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/9 23:35:40

大模型长文本中段遗忘归因与双向动态重排工程落地

长文本语言模型处理超长上下文时&#xff0c;普遍存在明显的“首尾偏置”&#xff08;Primacy and Recency Bias&#xff09;现象。这一现象在 2023 年斯坦福大学的研究中被命名为“Lost in the Middle”。当有效证据链或关键信息片段落在 Prompt 中间 30% 至 70% 的区间时&…

作者头像 李华
网站建设 2026/10/9 23:34:52

Python酒店管理系统数据库课程实战包:SQLite+PyQt5高分作业模板

简介&#xff1a;本资源是一套面向高校数据库课程学习者的Python酒店管理系统完整实践项目&#xff0c;适用于期末大作业、课程设计等场景&#xff0c;特别适合数据库原理与Python开发初学者快速上手并获得高分。项目采用MySQLPyQt5技术栈&#xff0c;涵盖用户登录、客房管理、…

作者头像 李华
网站建设 2026/10/9 23:34:15

md转PDF实测对比:在线、命令行、编辑器导出谁最快?

不夸张地说&#xff0c;我见过太多人第一次把 md 转 PDF 时&#xff0c;都栽在了同一个地方&#xff1a;在搜索引擎里翻来翻去&#xff0c;被一堆“一键转换”“在线免费”的广告带着跑&#xff0c;最后要么样式稀碎&#xff0c;要么折腾半小时还没搞定。我自己早期也这样&…

作者头像 李华
网站建设 2026/10/9 23:33:37

树的基本术语:从生活类比到代码落地的深度解析

1. 这不是背概念&#xff0c;而是理解数据结构的“树形思维”起点“树的一些基本术语”——看到这个标题&#xff0c;很多人第一反应是&#xff1a;这不就是教科书第一章里那些拗口又抽象的名词吗&#xff1f;节点、根、叶子、深度、高度、度、子树、兄弟、祖先、子孙……翻两页…

作者头像 李华
网站建设 2026/10/9 23:32:54

彻底吃透Promise:状态机、微任务与实战陷阱

不是我说&#xff0c;很多前端同行写了两三年代码&#xff0c;天天用Promise&#xff0c;可真要被人问一句“Promise到底是什么”就露怯。嘴上能说出“解决回调地狱”&#xff0c;心里其实对状态机、微任务、值穿透这些概念都是稀里糊涂的。这不怪大家&#xff0c;Promise这个A…

作者头像 李华