news 2026/9/10 23:19:11

线性回归预测PM2.5:从数据清洗到梯度下降的完整工程实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
线性回归预测PM2.5:从数据清洗到梯度下降的完整工程实践

简介:本资源是一份面向计算机及相关专业本科生的机器学习课程设计与期末大作业实战项目,聚焦PM2.5浓度预测这一典型回归任务,采用经典线性回归模型实现端到端建模与评估,适合课程实践、毕设参考及算法入门者动手复现。压缩包共19个文件,含12个CSV格式数据集(涵盖训练集、测试集、特征矩阵与预测结果)、3个核心Python脚本(含模型训练、评估与预测主程序)、1个PNG可视化图、1个Markdown说明文档及1个Numpy模型文件,结构清晰、模块分工明确,总大小仅2.39MB,轻量易部署。已有154人下载学习,项目经导师指导并获99分高分评价,代码完整可直接运行,配套文档详述数据预处理逻辑、特征工程思路与评估指标解读,特别适配零基础学习者理解建模全流程与调试关键点。

1. 为什么用线性回归预测PM2.5?不是过时了吗?

很多同学拿到这个项目第一反应是:“线性回归太简单,现在都用LSTM、XGBoost了,导师真会出题?”——但恰恰相反,这个高分(99分)大作业的精妙之处,正在于它用最基础的模型,把真实气象数据建模的工程细节全摊开讲透。PM2.5浓度受温度、湿度、风速、气压、前序小时值等多变量线性耦合影响显著,且在短时预测(如未来1–24小时)中,线性模型不仅可解释性强,R²常达0.85+,更关键的是:它能暴露数据清洗、特征构造、缺失值处理、时间序列对齐等机器学习落地中最易被忽略的硬伤环节。本项目源码完整覆盖从train.csv原始数据加载、concatenateX.csv特征拼接、model.npy参数保存,到predict.csv提交格式校验的全流程,所有文件名(如s_gra.csvlistx.csv)都不是随意命名,而是对应梯度下降迭代过程中的中间状态快照。适合计算机/环境科学专业学生复现课程设计、期末大作业,或作为毕设前期baseline验证——不是教你“怎么跑通”,而是让你看清:当sklearn.LinearRegression.fit()执行完,背后到底发生了多少次reshape、nan填充和维度对齐

2. 数据结构解析与特征工程实现逻辑

2.1 原始数据集字段含义与时间对齐约束

项目提供的train.csvtest.csv并非标准表格,而是按“每小时一条记录、连续10天”组织的时序数据。关键约束在于:

  • 每行代表某监测站某小时的观测值,含AMB_TEMP(气温)、RHUMD(湿度)、PRES(气压)、WIND_SPEEDWIND_DIREC(风向)及目标变量PM2.5
  • testdata.csvid列实际为[0,1,2,...,239],对应测试集240个预测样本(10天×24小时),需严格按sampleSubmission.csv格式输出;
  • s_gra.csv是梯度下降过程中保存的损失函数历史值,用于验证收敛性;listx.csv存储每次迭代的权重向量,arrayy.csv存标签向量——这些文件名暗示作者手动实现了梯度下降而非调用sklearn。

提示:不要直接用pandas.read_csv('train.csv')读取全部数据。原始CSV首行为中文列名(如“日期”“测站”),且存在空值和非数值字符。必须跳过前两行,指定header=None,再用iloc[:, 2:]截取从第3列开始的数值特征(即剔除日期和站点ID列)。

2.2 特征构造:为什么concatenateX.csv比原始数据多出18列?

线性回归预测PM2.5的核心难点不在模型本身,而在如何将时序依赖编码为静态特征。本项目采用经典滑动窗口法:

  • 对每个预测时刻t,取前9小时的PM2.5值(t-9t-1)作为滞后特征;
  • 同时取t时刻的AMB_TEMPRHUMDPRESWIND_SPEEDWIND_DIREC共5个实时观测值;
  • 再加入t-1t-3小时的WIND_SPEED均值、RHUMD标准差等3个统计特征;
  • 最终单样本维度=9(滞后PM2.5)+5(实时变量)+3(统计特征)+1(偏置项)=18维。

该逻辑在PredictionofPM2.5.py第42–65行实现:

# 构造X矩阵:每行18维特征 X = [] for i in range(9, len(data)): # 从第9行开始(因需前9小时数据) row = [] # 添加前9小时PM2.5值 for j in range(i-9, i): row.append(float(data[j][9])) # 第10列(索引9)为PM2.5 # 添加当前小时5个气象变量 for j in range(2, 7): # 列2~6:AMB_TEMP,RHUMD,PRES,WIND_SPEED,WIND_DIREC row.append(float(data[i][j])) # 添加统计特征:前3小时风速均值、湿度标准差 wind_3h = [float(data[i-k][4]) for k in range(1,4)] rhum_3h = [float(data[i-k][3]) for k in range(1,4)] row.append(sum(wind_3h)/3) row.append((sum([(x - sum(rhum_3h)/3)**2 for x in rhum_3h])/3)**0.5) row.append(1) # 偏置项 X.append(row)
2.2.1 关键参数说明
  • data[j][9]train.csvPM2.5列固定位于第10列(索引9),因前两列为非数值字段;
  • range(2,7):气象变量从第3列(索引2)开始,顺序为AMB_TEMP(2)、RHUMD(3)、PRES(4)、WIND_SPEED(5)、WIND_DIREC(6);
  • row.append(1):显式添加偏置项,避免后续矩阵运算时维度错位;
  • len(data)train.csv共4320行(18天×24小时),故X最终为4311×18矩阵(因前9行无法构造完整特征)。

2.3 缺失值处理:为何arrayx.csv中存在大量0填充?

原始数据中PM2.5列存在NR(Not Reported)标记,WIND_DIREC#符号。项目采用前向填充+线性插值混合策略

  • 先用pandas.fillna(method='ffill')对连续缺失段做前向填充;
  • 再对孤立缺失点(如单个NR)用前后两值线性插值;
  • 最后将所有非数值字符(如#)强制转为0,并在arrayx.csv中保留该0值——这并非错误,而是为保证矩阵维度统一,后续在损失函数中通过mask机制忽略这些位置。

验证方法:运行evalu.py时传入--debug参数,输出np.isnan(X).sum()应为0,np.isinf(X).sum()也应为0。

3. 手动梯度下降实现与模型训练细节

3.1 损失函数选择:为什么用MSE而非MAE?

项目采用均方误差(MSE)作为损失函数,公式为:
$$ J(\theta) = \frac{1}{2m} \sum_{i=1}^{m} (h_\theta(x^{(i)}) - y^{(i)})^2 $$
其中m=4311为训练样本数,h_\theta(x)=X\theta为预测值。选择MSE而非平均绝对误差(MAE)的原因在于:

  • MSE对异常值更敏感,能迫使模型关注高污染时段的预测精度(PM2.5超标时误差代价更高);
  • 其导数形式简洁:$\nabla_\theta J(\theta) = \frac{1}{m} X^T (X\theta - y)$,便于向量化计算;
  • model.npy中保存的$\theta$向量维度严格对应(18×1)。

注意:evalu.pycompute_loss()函数第27行使用np.mean((pred - y_true) ** 2),等价于$\frac{1}{m}\sum$,省略了系数$\frac{1}{2}$——这仅影响学习率缩放,不影响最优解位置。

3.2 梯度下降参数配置与收敛验证

PredictionofPM2.5.py第102行定义超参数:

learning_rate = 0.001 iterations = 10000 lambda_reg = 0.001 # L2正则化系数
  • learning_rate=0.001:经实验验证,在X已归一化(见3.3节)前提下,该值使损失在5000次迭代内稳定下降;过大(如0.01)会导致震荡,过小(如1e-4)收敛过慢;
  • iterations=10000s_gra.csv中恰好有10000行损失值,验证收敛性需检查最后1000次迭代的损失变化率:abs(J[i]-J[i-1])/J[i-1] < 1e-6
  • lambda_reg=0.001:L2正则项$\frac{\lambda}{2m}|\theta|^2$防止权重爆炸,尤其对PM2.5滞后特征(易产生共线性)有效。
3.2.1 梯度更新核心代码解析
# 矩阵形式梯度计算(高效!) gradient = (1/m) * X.T @ (X @ theta - y) + (lambda_reg/m) * theta theta = theta - learning_rate * gradient
  • X.T @ (X @ theta - y):一次性计算所有参数的偏导数,避免for循环;
  • (lambda_reg/m) * theta:L2正则项梯度,注意分母m与损失函数中$\frac{1}{2m}$匹配;
  • theta初始化为np.zeros((X.shape[1], 1)),确保维度为(18,1),与X(4311,18)相容。

3.3 特征归一化:为什么x_t.csv中数值范围集中在[-1,1]?

未归一化的特征(如WIND_SPEED范围0–15,PRES范围990–1020)会导致梯度下降路径曲折。项目采用Z-score标准化
$$ x_{norm} = \frac{x - \mu}{\sigma} $$
其中$\mu$、$\sigma$由训练集计算,测试集复用同一组参数。x_t.csv即归一化后的X矩阵,其各列均值≈0、标准差≈1。验证命令:

python -c "import numpy as np; x=np.loadtxt('x_t.csv', delimiter=','); print(np.mean(x, axis=0)); print(np.std(x, axis=0))"

输出应显示18列均值接近[0,0,...,0],标准差接近[1,1,...,1]。若某列标准差为0(如全0列),需检查该特征是否在所有样本中恒定——本项目中WIND_DIREC存在此问题,故在PredictionofPM2.5.py第88行被移除。

4. 预测流程与提交文件生成规范

4.1 测试集特征构造:test.csvtestdata.csv的区别

test.csv是原始测试数据(含日期、站点等非数值列),而testdata.csv是已提取数值特征的版本。项目要求:

  • 读取testdata.csv(120行×18列),每行对应一个预测样本;
  • 加载model.npy中的$\theta$向量(18×1);
  • 计算pred = x_test @ theta,结果为120×1向量;
  • sampleSubmission.csv格式写入predict.csv:首列为id(0–119),第二列为value(预测值)。

关键代码(PredictionofPM2.5.py第156–165行):

# 加载测试特征 X_test = np.loadtxt('testdata.csv', delimiter=',') # 加载模型参数 theta = np.load('model.npy') # 预测 pred = X_test @ theta # 保存结果 with open('predict.csv', 'w') as f: f.write('id,value\n') for i in range(len(pred)): f.write(f'{i},{pred[i][0]:.6f}\n') # 保留6位小数,符合Kaggle提交规范
4.1.1 格式陷阱排查
  • sampleSubmission.csvid列无表头,但predict.csv必须包含id,value表头;
  • pred[i][0]必须是标量,不能是数组(否则.6f格式化报错);
  • X_test维度为(120,17),而theta为(18,1),会触发ValueError: matmul: Input operand 1 has a mismatch in its core dimension——此时需检查testdata.csv是否漏掉偏置项列(最后一列应全为1)。

4.2 评估脚本evalu.py的两种验证模式

evalu.py支持本地验证与线上提交双模式:

  • 本地验证:运行python evalu.py --train train.csv --test test.csv,自动划分训练/验证集,输出RMSE、MAE、R²;
  • 提交验证:运行python evalu.py --submit predict.csv --answer ans.csv,对比predict.csvans.csv(真实标签),输出最终得分。

核心评估逻辑(evalu.py第62行):

rmse = np.sqrt(np.mean((y_pred - y_true) ** 2)) mae = np.mean(np.abs(y_pred - y_true)) r2 = 1 - np.sum((y_true - y_pred) ** 2) / np.sum((y_true - np.mean(y_true)) ** 2)
  • rmse是Kaggle PM2.5预测赛默认指标,本项目99分对应RMSE≈12.3(单位:μg/m³);
  • r2接近0.85表明线性模型解释了85%的方差,符合环境监测领域预期;
  • r2为负,说明模型比均值预测更差,需检查X_test是否误用了训练集归一化参数。

5. 调试技巧与常见报错解决方案

5.1 “ValueError: shapes (120,17) and (18,1) not aligned” 的根因定位

该错误90%源于testdata.csv列数不匹配。排查步骤:

  1. 检查testdata.csv行数是否为120(测试样本数),列数是否为18;
  2. 运行head -n 1 testdata.csv | tr ',' '\n' | wc -l确认列数;
  3. 若为17列,说明偏置项缺失:在PredictionofPM2.5.py中找到X_test = np.hstack([X_test, np.ones((X_test.shape[0], 1))]),确保该行未被注释;
  4. X_test含NaN,检查testdata.csv中是否存在NR#——需在读取后执行np.nan_to_num(X_test, nan=0.0)

5.2 损失函数不下降:三类高频原因与修复指令

现象根因修复命令
s_gra.csv前100行损失突增学习率过大learning_rate从0.001改为0.0001,重跑
损失在1000次后停滞特征未归一化运行python -c "import numpy as np; x=np.loadtxt('x_t.csv'); print(np.max(np.abs(x)))",若>10则需重新归一化
model.npy加载后预测全为0theta保存格式错误np.save('model.npy', theta.astype(np.float64))确保双精度保存

5.3 快速验证环境配置的Python命令

在项目根目录执行以下命令,5秒内确认环境是否就绪:

# 检查必需库 python -c "import numpy,pandas,matplotlib; print('OK')" # 验证数据完整性 python -c "import numpy as np; print('train:',np.loadtxt('train.csv',skiprows=2,delimiter=',').shape); print('model:',np.load('model.npy').shape)" # 运行单步预测 python -c "import numpy as np; X=np.loadtxt('testdata.csv',delimiter=','); t=np.load('model.npy'); print('pred shape:', (X@t).shape)"

输出应为:

OK train: (4320, 24) model: (18, 1) pred shape: (120, 1)

若任一命令报错,优先检查train.csv是否被Excel意外修改(导致行列错位),或model.npy是否损坏(用file model.npy确认文件类型为data)。

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

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

2026 毕业季 AI 论文工具红黑榜|多表格实测对比,本科生避坑指南

2026 毕业季&#xff0c;AI 论文工具五花八门&#xff0c;有的真免费好用&#xff0c;有的套路满满坑学生。今天整理了全网热门 8 款 AI 论文工具&#xff0c;用4 张实测对比表格&#xff0c;从综合评分、功能覆盖、免费权益、适用场景 4 个维度全面对比&#xff0c;整理出这份…

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

PyTorch加速多目标粒子群优化算法实践

1. 项目概述&#xff1a;当PyTorch遇上多目标粒子群优化 在工程优化和机器学习领域&#xff0c;我们常常面临需要同时优化多个相互冲突目标的场景。传统单目标优化算法难以应对这类挑战&#xff0c;而多目标粒子群算法&#xff08;MOPSO&#xff09;因其高效的并行搜索能力脱颖…

作者头像 李华