数据预处理:异常值检测与修复、数据平滑、数据插补

各位同学,咱们今天聊点实在的。数据预处理,说白了就是给原始交通流数据“洗澡”。你想想看,路口的线圈检测器、微波雷达、视频摄像头,这些设备采集回来的数据,哪能那么干净?我做了十几年交通工程,见过太多“脏数据”了——线圈被大车压坏、雷达被树叶遮挡、视频在雨天模糊……这些数据如果不处理,后面的模型就是“垃圾进,垃圾出”。

我个人习惯,拿到数据的第一件事,不是急着建模,而是先做三件事:异常值检测、数据平滑、缺失值插补。这三步走完,数据才算“能用”。

一、异常值检测与修复

什么是异常值?简单说,就是那些明显不符合交通规律的数据点。比如,一条城市主干道,平时流量每小时2000辆,突然蹦出一个10000辆——这明显是设备抽风了。

我常用的方法有三种:

  1. 3σ原则(拉依达准则):假设数据服从正态分布,超出均值±3倍标准差的值,视为异常。这个方法简单粗暴,但适合流量、速度这类近似正态分布的参数。
  2. 箱线图法(IQR):用四分位距来判定。低于Q1-1.5×IQR或高于Q3+1.5×IQR的点,就是异常。这个方法对偏态分布更鲁棒。
  3. 交通工程经验阈值:比如,城市道路速度不可能超过120km/h,单车道流量不可能超过2200辆/小时。超出物理极限的,直接标红。

避坑指南:我曾经在一个项目中,用3σ原则检测异常,结果把早晚高峰的正常高流量也误判了。后来改用“滑动窗口+局部阈值”才解决。记住:全局阈值不一定适用,要结合时段、路段特性来调整。

修复异常值,我一般用两种策略:

  • 直接剔除:如果异常点很少(比如<1%),直接删掉,用前后值插补。
  • 替换为阈值边界值:比如速度异常高,就替换为路段限速值。这样不会破坏数据连续性。
# Python示例:3σ异常检测
import numpy as np
import pandas as pd

def detect_outliers_3sigma(data, column):
    mean = data[column].mean()
    std = data[column].std()
    lower = mean - 3 * std
    upper = mean + 3 * std
    outliers = data[(data[column] < lower) | (data[column] > upper)]
    return outliers.index.tolist()

# 修复:用前后均值替换
def fix_outliers(data, column, outlier_idx):
    for idx in outlier_idx:
        if idx > 0 and idx < len(data)-1:
            data.loc[idx, column] = (data.loc[idx-1, column] + data.loc[idx+1, column]) / 2
    return data

二、数据平滑:移动平均与指数平滑

数据平滑,说白了就是“去噪”。交通流数据里有很多随机波动——比如一辆车突然刹车、一个行人横穿马路,这些都会造成数据毛刺。平滑的目的,是提取出真正的交通趋势。

移动平均(Moving Average):我最常用的方法。取一个窗口(比如5分钟、15分钟),计算窗口内的平均值。窗口越大,曲线越平滑,但也会丢失细节。

我的经验:对于5分钟粒度的流量数据,窗口选3~5个点(即15~25分钟)效果最好。太短了平滑不够,太长了会把高峰削平。

# 移动平均示例
def moving_average(data, window=5):
    return data.rolling(window=window, center=True).mean()

指数平滑(Exponential Smoothing):这个比移动平均更“聪明”。它给近期数据更高的权重,远期数据权重递减。参数α(平滑系数)控制衰减速度:α越大,越关注近期数据。

我记得有一次做高速公路速度预测,移动平均总是滞后于真实变化。换成指数平滑后,预测的实时性明显提升。为什么?因为指数平滑对最新数据更敏感。

# 指数平滑示例
def exponential_smoothing(data, alpha=0.3):
    result = [data[0]]
    for i in range(1, len(data)):
        result.append(alpha * data[i] + (1 - alpha) * result[-1])
    return result
方法 优点 缺点 适用场景
移动平均 简单直观,计算快 滞后性明显 离线分析、历史数据
指数平滑 实时性好,权重灵活 参数α需调优 在线预测、实时系统

三、数据插补方法

数据缺失,是交通数据里的家常便饭。设备故障、通信中断、维护检修……都会造成数据空洞。插补,就是把这些“洞”补上。

我常用的插补方法,按复杂度排序:

  1. 前向填充(Forward Fill):用上一个有效值填充。简单,但误差大。适合短时间缺失(比如1~2个时间点)。
  2. 线性插值(Linear Interpolation):用缺失点前后两个有效值,做线性拟合。比前向填充准,但假设数据是线性变化的——交通流其实是非线性的。
  3. 时间序列插值(如ARIMA、STL分解):考虑周期性、趋势性。比如,周一的早高峰缺失,可以用上周一的同期数据来补。这是我最推荐的方法。

注意:千万不要用全局均值来插补!我曾经见过一个项目,用全年平均流量去补缺失的晚高峰数据,结果模型完全失真。交通流有强烈的日周期、周周期,必须考虑时间上下文。

# 线性插值示例
import pandas as pd

def linear_interpolation(data, column):
    return data[column].interpolate(method='linear')

# 周期插值:用上周同一天同时段数据填充
def periodic_interpolation(data, column, period=7*288):  # 假设5分钟粒度,7天
    for i in range(len(data)):
        if pd.isna(data.loc[i, column]):
            if i >= period:
                data.loc[i, column] = data.loc[i - period, column]
    return data

知识体系总览

下面这张图,是我自己总结的数据预处理流程。你把它打印出来贴在工位上,做项目时对照着来,基本不会出错。

交通流数据预处理流程 原始交通流数据 步骤1:异常值检测与修复 步骤2:数据平滑 步骤3:数据插补 清洗后的高质量数据 3σ / IQR / 经验阈值 移动平均 / 指数平滑 前向填充 / 线性插值 / 周期插值 注意:分时段阈值 注意:窗口大小选择 注意:考虑周期特性

嗯,到这里,数据预处理的三个核心步骤就讲完了。你可能会问:这三步的顺序能不能换?我个人建议,先做异常检测和修复,再做平滑,最后插补。因为异常值会影响平滑效果,而平滑后的数据插补会更稳定。

好了,这一节的内容就是这些。记住,数据预处理不是“锦上添花”,而是“雪中送炭”。你花80%的时间在数据清洗上,后面建模就会省下200%的麻烦。