3. 数据采集与预处理:数据来源、清洗、缺失值处理与标准化

好,咱们进入第三章。这一章聊的是数据预处理,说白了就是“把脏活累活干漂亮”。很多同学觉得建模、调参才是技术活,预处理就是体力活。我刚开始也这么想,直到有一次在项目里,因为一个传感器数据漂移没处理好,模型直接跑偏了20%的精度。嗯,从那以后,我再也不敢小看这一步了。

3.1 数据来源:监测站与遥感

空气质量数据从哪来?主要就两条路:地面监测站和卫星遥感。

地面监测站是最直接的。每个城市都有国控点、省控点,甚至有些企业自己建了微型站。这些站点实时采集PM2.5、PM10、SO₂、NO₂、CO、O₃这些常规指标。我个人习惯,拿到数据第一件事就是看时间戳——很多站点的数据上报有延迟,或者干脆跳过了某个小时,这坑我踩过。

卫星遥感呢,覆盖广,但精度差点。比如MODIS、VIIRS这些卫星,能反演气溶胶光学厚度(AOD),再换算成PM2.5浓度。说白了,遥感数据适合做大范围趋势分析,但具体到某个街道,还是得靠地面站。

我建议,做项目时尽量把两者结合起来。地面站数据做“真值”,遥感数据做“空间插值”。你想想看,监测站再密,也不可能每个小区都建一个,这时候遥感就能补上空白。

小技巧: 拿到遥感数据后,记得检查一下分辨率。有些产品是1公里网格,有些是10公里。分辨率不匹配,后续融合会很麻烦。

3.2 数据清洗:把垃圾数据筛出去

数据清洗,说白了就是“去伪存真”。我见过最离谱的情况——某个监测站连续三天报PM2.5为0,后来发现是传感器被鸟粪糊住了。这种数据不清理,模型学出来的全是错的。

常见的脏数据有这几类:

  • 重复数据:同一时间戳出现多条记录。一般是采集程序bug导致的。
  • 异常值:比如PM2.5突然飙到1000,但周围站点都正常。这大概率是传感器故障。
  • 格式错误:时间戳格式不统一,有的用“2024-01-01 08:00”,有的用“2024/01/01 8:00”。

怎么处理?我一般用三步走:

  1. 去重:按时间戳和站点ID去重,保留第一条。
  2. 范围过滤:比如PM2.5的正常范围是0-500,超出这个区间的直接标记为异常。
  3. 一致性检查:比如温度不能是负数(除非在极地),风速不能是负值。
核心原则: 宁可删掉可疑数据,也不要让脏数据混进模型。我曾经因为保留了一小段异常数据,导致整个模型的泛化能力下降,后来排查了三天才找到原因。

3.3 缺失值处理:别让空值毁了你的模型

缺失值在空气质量数据里太常见了。设备断电、网络中断、维护检修,都会导致数据缺失。你想想看,一个时间序列模型,中间缺了几个点,怎么算?

处理缺失值,常用的方法有这几种:

方法 适用场景 优缺点
直接删除 缺失比例很小(<5%) 简单粗暴,但会损失样本
均值/中位数填充 数据分布稳定,缺失随机 计算快,但会降低方差
前向/后向填充 时间序列数据,短时间缺失 保留趋势,但长缺失会失真
插值法(线性/样条) 缺失段较短,数据平滑 效果较好,但计算量稍大
模型预测填充 缺失比例高,数据复杂 精度高,但容易过拟合

我个人习惯,对于短时间缺失(比如连续缺1-2小时),用线性插值就够了。如果缺失超过6小时,我会用前向填充,或者干脆把这段数据标记为“不可用”。

注意: 千万不要用全局均值填充时间序列数据!比如PM2.5有明显的日变化和季节变化,用全局均值会把这种规律抹掉。我曾经见过一个项目,用均值填充后,模型的预测能力直接腰斩。

代码示例,用pandas处理缺失值:

import pandas as pd
import numpy as np

# 读取数据
df = pd.read_csv('air_quality.csv', parse_dates=['timestamp'])

# 检查缺失值
print(df.isnull().sum())

# 线性插值(短时间缺失)
df['pm25'] = df['pm25'].interpolate(method='linear', limit=6)

# 前向填充(长时间缺失)
df['pm25'] = df['pm25'].fillna(method='ffill', limit=12)

# 标记剩余缺失值
df['pm25_missing'] = df['pm25'].isnull().astype(int)

3.4 数据标准化:让不同量纲的数据能一起玩

标准化,说白了就是把不同尺度的数据拉到同一个量级。PM2.5的单位是μg/m³,范围0-500;温度是℃,范围-10到40;风速是m/s,范围0-20。如果不做标准化,模型会天然偏向数值大的特征。

常用的标准化方法:

  • Z-score标准化:减去均值,除以标准差。适合数据近似正态分布的情况。
  • Min-Max归一化:缩放到[0,1]区间。适合数据有明确边界的情况。
  • Robust标准化:用中位数和四分位距。适合数据有较多异常值的情况。

我建议,对于空气质量数据,优先用Robust标准化。为什么?因为空气质量数据经常有异常峰值(比如沙尘暴、烟花爆竹),这些异常值会严重拉偏均值和标准差。Robust标准化用中位数,抗干扰能力强得多。

避坑指南: 标准化参数(均值、标准差、最小值、最大值)一定要从训练集计算,然后应用到验证集和测试集。千万不要用全局数据计算,否则会造成数据泄露。我曾经犯过这个错,模型在测试集上表现好得离谱,一上线就崩了。

代码示例:

from sklearn.preprocessing import RobustScaler

# 初始化标准化器
scaler = RobustScaler()

# 从训练集拟合参数
train_scaled = scaler.fit_transform(train_data)

# 应用到验证集和测试集
val_scaled = scaler.transform(val_data)
test_scaled = scaler.transform(test_data)

好了,这一章的内容就这些。数据预处理虽然琐碎,但绝对是决定模型上限的关键一步。下一章我们会聊特征工程,到时候你会看到,预处理做得好,特征工程事半功倍。