3、数据采集与预处理:噪声监测设备介绍、数据采集频率与时长、缺失值处理、异常值检测与修正

好,咱们进入第三章。说实话,数据采集和预处理这部分,看着不像模型训练那么“高大上”,但我要跟你掏心窝子说一句:这步要是没做好,后面所有工作都是白搭。我在好几个项目里都吃过这个亏,有一次辛辛苦苦跑了一个星期的模型,结果发现是传感器坏了,数据全是废的……嗯,从那以后,我对数据预处理就格外上心。

3.1 噪声监测设备介绍

先聊聊设备。环境噪声监测,说白了就是用耳朵的“电子版”去听这个世界。常用的设备有这么几类:

  • 声级计:最基础的设备,测瞬时声压级。我习惯把它比作“温度计”,简单直接。
  • 噪声监测终端:能连续工作,带数据存储和传输功能。城市网格化监测用的就是它。
  • 多通道分析仪:能同时测多个点位,还能做频谱分析。搞科研或者做噪声源识别时常用。

这里有个关键参数——频率计权。人耳对不同频率的声音敏感度不一样,所以设备通常有 A、C、Z 三种计权网络。A 计权最接近人耳,我们平时说的“分贝”其实默认就是 dBA。我个人建议,做环境噪声预测时,优先用 A 计权数据,因为法规标准基本都是按这个来的。

重要提醒:设备选型时,一定要看它的 动态范围本底噪声。动态范围不够,大信号会削波;本底噪声太高,小信号就测不准。我见过有人用本底噪声 35dBA 的设备去测 30dBA 的夜间环境……那数据基本没法用。

3.2 数据采集频率与时长

这个问题,我每次带新人时都会重点讲。采集频率和时长,直接决定了你数据的“分辨率”和“代表性”。

采集频率,就是每秒采多少个点。环境噪声一般用 1秒0.1秒 的间隔。为什么?因为交通噪声、施工噪声变化快,间隔太长会漏掉峰值。我做过一个对比实验:用 1秒 间隔和 10秒 间隔同时测同一段马路,结果 10秒 间隔的数据把好几辆重型卡车的噪声峰值都“平滑”掉了,模型预测精度直接掉了 15%。

采集时长,这个要看你的应用场景:

场景 建议时长 原因
交通噪声 连续 24 小时以上 覆盖早晚高峰和夜间低谷
施工噪声 至少一个完整施工周期 不同工序噪声差异大
工业噪声 连续 48 小时 设备启停、工况变化
短期监测 每次不少于 10 分钟 保证统计稳定性

我的小技巧:如果条件允许,尽量多采几天数据。我曾经为了一个机场噪声项目,连续采集了 7 天数据。结果发现第 3 天和第 5 天的风向不同,噪声传播路径完全不一样。多亏了这 7 天数据,模型才学会了“看风向”。

3.3 缺失值处理

数据缺失,太常见了。设备断电、通信故障、人为误操作……原因五花八门。处理缺失值,我一般按这个优先级来:

  1. 直接删除:如果缺失比例小于 5%,且是随机缺失,直接删掉那几行数据。简单粗暴,但有效。
  2. 线性插值:缺失时间短(比如连续缺失不超过 5 个点),用前后数据线性填充。环境噪声变化相对连续,这个方法挺靠谱。
  3. 均值/中位数填充:用同一天同一时段的均值来补。注意,别用全天均值,那会把昼夜差异抹掉。
  4. 模型预测填充:缺失比例高(比如超过 20%),或者缺失有规律时,用 KNN 或时间序列模型来预测缺失值。

举个代码例子,用线性插值处理 1 秒间隔的噪声数据:

import pandas as pd

# 假设 data 是包含 'time' 和 'noise' 两列的 DataFrame
data['time'] = pd.to_datetime(data['time'])
data = data.set_index('time')

# 线性插值,限制最大连续缺失为 5 个点
data['noise'] = data['noise'].interpolate(method='linear', limit=5)

# 如果还有缺失,用前后 1 小时的中位数填充
data['noise'] = data['noise'].fillna(
    data['noise'].rolling(window=3600, center=True).median()
)

注意:千万不要用全局均值去填充缺失值!我见过有人这么干,结果把夜间 30dBA 的安静时段填成了白天的 55dBA,模型直接学歪了。缺失值处理一定要考虑 时间上下文

3.4 异常值检测与修正

异常值,就是那些“离谱”的数据点。比如半夜突然蹦出个 120dBA,那八成是设备被鸟撞了,或者有人在传感器旁边放了个鞭炮。

检测异常值,我常用三种方法:

  • 3σ 原则:数据服从正态分布时,超过均值 ±3 倍标准差的值视为异常。简单,但环境噪声往往不是严格正态的。
  • IQR 方法:用四分位距。低于 Q1-1.5×IQR 或高于 Q3+1.5×IQR 的算异常。这个方法对偏态分布更鲁棒。
  • 滑动窗口法:以当前点为中心,取前后 N 个点,如果当前点偏离窗口均值超过 3 倍窗口标准差,就标记为异常。这个方法我最常用,因为它能适应噪声的时变特性。

修正异常值,我的原则是:能修则修,不能修就删。修正方法跟缺失值类似,用插值或者窗口均值替换。但要注意,如果异常值连续出现(比如设备坏了半小时),那就别修了,直接删掉那一段。

来看一个滑动窗口检测的代码:

import numpy as np

def detect_anomalies(series, window=300, threshold=3):
    """
    滑动窗口异常检测
    series: 噪声数据序列
    window: 窗口大小(秒)
    threshold: 阈值倍数
    """
    anomalies = np.zeros(len(series), dtype=bool)
    for i in range(window, len(series) - window):
        window_data = series[i-window:i+window+1]
        mean = np.mean(window_data)
        std = np.std(window_data)
        if abs(series[i] - mean) > threshold * std:
            anomalies[i] = True
    return anomalies

# 使用示例
anomaly_mask = detect_anomalies(data['noise'].values, window=300, threshold=3)
data['noise'][anomaly_mask] = np.nan  # 先置为缺失
data['noise'] = data['noise'].interpolate(method='linear')  # 再插值修正

避坑指南:我曾经处理过一组数据,发现每天下午 3 点准时出现一个 100dBA 的“异常值”。查了半天,原来是清洁工每天那个时间用高压水枪冲洗传感器附近的墙壁。这种“伪异常”其实是真实事件,不能随便删。所以,异常值检测一定要结合现场日志,别光靠算法。

3.5 本章知识体系

说了这么多,咱们用一张图把核心逻辑串起来:

数据采集与预处理知识体系 数据采集 设备选型(声级计/终端/分析仪) → 频率计权(A/C/Z) → 采集频率(1s/0.1s) → 采集时长(24h/周期) 数据预处理 缺失值处理(删除/插值/均值/模型) → 异常值检测(3σ/IQR/滑动窗口) → 异常值修正(插值/删除) 高质量数据集 连续、完整、无异常 → 可直接用于模型训练与验证 常见坑点 设备本底噪声过高 常见坑点 缺失值用全局均值填充 常见坑点 异常值不结合现场日志

这张图把咱们这章的核心逻辑都串起来了。从设备选型开始,到采集参数设置,再到缺失值和异常值的处理,最终得到一份干净、可靠的数据集。每一步都有坑,但每一步也都有应对方法。

好了,数据采集和预处理就聊到这儿。记住一句话:垃圾数据进,垃圾模型出。把基础打牢,后面的路才走得稳。