3、野点识别与处理:野点定义与成因、基于统计学的野点检测(3σ原则、箱线图法)、基于物理阈值的野点检测

聊到数据清洗,野点(Outlier)是绕不开的话题。我做了这么多年测风数据处理,可以说,80%的脏数据问题都出在野点上。你想想看,一个传感器偶尔抽风,记录了一个风速80m/s的数值——这在绝大多数风电场根本不可能。如果不处理,后面算出来的发电量、湍流强度全都会跑偏。

所以这一节,咱们就专门来啃这块硬骨头。

3.1 野点是什么?它从哪来?

野点,说白了就是那些明显偏离正常数据范围的异常值。它不是随机噪声,而是实实在在的错误数据。

野点的常见成因:

  • 传感器故障:比如风速计轴承卡涩、风向标卡死。我在内蒙古一个项目上遇到过,某台风速计连续三天输出恒定的12.3m/s,一看就是卡住了。
  • 结冰/污染:叶片结冰后,风速计转不动,输出值骤降或归零。高海拔项目尤其常见。
  • 信号传输干扰:线路老化、雷击、电磁干扰,都会导致数据跳变。
  • 维护操作:工作人员登塔检修时,传感器被遮挡或触碰,产生瞬时异常值。
  • 数据记录错误:采集器时钟漂移、存储介质损坏,导致数据错位或乱码。

核心认知:野点不是「极端天气事件」,而是「错误数据」。两者要区分开。极端风速虽然罕见,但物理上可能发生;野点则是物理上不可能或极不可能的值。

3.2 基于统计学的野点检测

统计学方法是我最常用的第一道防线。它不需要知道传感器的物理参数,纯粹从数据分布入手,把那些「不合群」的点揪出来。

3.2.1 3σ原则(拉依达准则)

这个方法的前提是数据服从正态分布。在正态分布中,99.73%的数据落在均值±3个标准差范围内。超出这个范围的,就视为野点。

计算公式:

下限 = μ - 3σ
上限 = μ + 3σ
其中 μ 为均值,σ 为标准差

代码示例(Python):

import numpy as np

def detect_outliers_3sigma(data):
    mean = np.mean(data)
    std = np.std(data)
    lower = mean - 3 * std
    upper = mean + 3 * std
    outliers = (data < lower) | (data > upper)
    return outliers, lower, upper

# 示例:10分钟平均风速
wind_speed = np.array([5.2, 5.8, 6.1, 5.5, 12.8, 5.9, 6.0, 5.7])
outliers, low, up = detect_outliers_3sigma(wind_speed)
print(f"野点标记:{outliers}")  # 第5个点(12.8)被标记为True

注意:3σ原则对样本量有要求,一般建议n≥30。样本太少时,均值和标准差本身就不稳定,容易误判。我曾经在只有10个样本的小数据集上用过,结果把正常值也标成了野点——教训啊。

3σ原则的局限性:

  • 对数据分布敏感。如果数据本身偏态严重,3σ会漏掉很多野点。
  • 野点本身会拉大标准差,导致「掩蔽效应」——野点太多时,反而检测不出来。

3.2.2 箱线图法(四分位距法)

这个方法比3σ更稳健。它不依赖均值和标准差,而是用中位数和四分位数来定义正常范围。说白了,它不怕野点「污染」统计量。

计算公式:

IQR = Q3 - Q1
下限 = Q1 - 1.5 * IQR
上限 = Q3 + 1.5 * IQR
其中 Q1 为下四分位数(25%分位),Q3 为上四分位数(75%分位)

代码示例(Python):

import numpy as np

def detect_outliers_iqr(data):
    q1 = np.percentile(data, 25)
    q3 = np.percentile(data, 75)
    iqr = q3 - q1
    lower = q1 - 1.5 * iqr
    upper = q3 + 1.5 * iqr
    outliers = (data < lower) | (data > upper)
    return outliers, lower, upper

# 示例:包含野点的风速数据
wind_speed = np.array([5.2, 5.8, 6.1, 5.5, 25.0, 5.9, 6.0, 5.7, 0.1])
outliers, low, up = detect_outliers_iqr(wind_speed)
print(f"野点标记:{outliers}")  # 第5个(25.0)和第9个(0.1)被标记

我的习惯:在测风数据清洗中,我通常先用箱线图法做第一轮检测,再用3σ原则做第二轮。两者结合,能覆盖大多数情况。箱线图法对偏态分布更友好,而3σ对对称分布更敏感。

箱线图法的优势:

  • 不受极端值影响,稳健性强。
  • 不需要数据服从特定分布。
  • 可视化直观——箱线图一看就懂。

3.3 基于物理阈值的野点检测

统计学方法虽然好用,但它不懂物理。比如一个风速30m/s,在沿海台风区可能是正常值,但在内陆平原就是野点。这时候就需要物理阈值出场了。

物理阈值的设定依据:

参数 常见物理阈值 说明
风速 0 ~ 40 m/s(陆上)
0 ~ 60 m/s(海上)
超过该范围基本不可能
风向 0° ~ 360° 超出即无效
温度 -40°C ~ 60°C 根据项目地气候调整
气压 850 ~ 1080 hPa 海平面气压范围
湿度 0% ~ 100% 超出即无效

代码示例:

def detect_outliers_physical(wind_speed, wind_direction, temp, pressure, humidity):
    flags = []
    for ws, wd, t, p, h in zip(wind_speed, wind_direction, temp, pressure, humidity):
        flag = False
        if ws < 0 or ws > 40:      # 陆上风速阈值
            flag = True
        if wd < 0 or wd > 360:     # 风向阈值
            flag = True
        if t < -40 or t > 60:      # 温度阈值
            flag = True
        if p < 850 or p > 1080:    # 气压阈值
            flag = True
        if h < 0 or h > 100:       # 湿度阈值
            flag = True
        flags.append(flag)
    return np.array(flags)

关键提醒:物理阈值不是死的。我在青藏高原做项目时,当地冬季气温能到-45°C,所以我把温度下限调到了-50°C。而在海南海上项目,风速上限我设到了60m/s。一定要根据项目地实际情况调整。

3.4 三种方法的对比与选择

方法 优点 缺点 适用场景
3σ原则 简单、计算快 依赖正态分布,易受野点影响 数据量大、分布对称时
箱线图法 稳健、不依赖分布 对尾部数据不敏感 偏态分布、含少量野点时
物理阈值法 物理意义明确、零误判 需要先验知识、阈值难定 所有场景的基础过滤

我的建议流程:

  1. 先用物理阈值法,把明显不可能的数据剔除(比如风速负值、风向大于360°)。
  2. 再用箱线图法,检测统计意义上的异常点。
  3. 最后用3σ原则做补充,特别是对对称分布的数据。

避坑指南:我曾经在一个项目上,直接用3σ原则处理10分钟平均风速,结果把台风期间的所有数据都标成了野点——因为台风风速远高于平时均值+3σ。后来我学乖了:先按季节、按风速段分组,再分别检测。这样既保留了极端天气事件,又剔除了真正的野点。

3.5 知识体系总览

下面这张图,把野点检测的三种方法串起来了。你可以把它当作一个决策树来用。

野点检测方法体系 原始测风数据 物理阈值法 箱线图法(IQR) 3σ原则 风速 0~40m/s 风向 0°~360° 温度 -40°C~60°C Q1 - 1.5*IQR 以下 Q3 + 1.5*IQR 以上 μ - 3σ 以下 μ + 3σ 以上 推荐流程:物理阈值 → 箱线图法 → 3σ原则

嗯,到这里野点检测的三种方法就讲完了。你可能会问:检测出来之后怎么处理?是直接删除,还是替换,还是标记保留?这个我们后面会专门讲。但有一点我现在就可以告诉你:永远不要自动删除野点。先标记,再人工复核,这是底线。

最后一个小技巧:在正式处理之前,先把数据画成散点图或时序图。肉眼扫一遍,往往能发现算法漏掉的野点。我每次做数据清洗,第一件事就是「看图」。机器再聪明,也比不上人眼对「不对劲」的直觉。


公众号:蓝海资料掘金营,微信deep3321