第2章:数据预处理基础——缺失值处理与异常值检测

各位同学好,我是你们的老朋友。上一章我们聊了数据采集和基础概览,今天咱们进入一个更“脏活累活”的阶段——数据预处理。

说实话,我在电力行业摸爬滚打这么多年,见过太多“漂亮”的原始数据,一跑模型就崩。为什么?因为数据里藏着各种“坑”。缺失值、异常值,这两个东西不处理好,后面的分析全是白搭。今天我就把压箱底的经验掏出来,咱们一个一个说。

2.1 缺失值处理:别让“空”坑了你

电力数据里,缺失值太常见了。传感器故障、通信中断、人为误操作……原因五花八门。你想想看,一个变电站的负荷数据,某天突然跳了个空,你怎么办?

我个人习惯,先看缺失比例。如果缺失超过50%,这列数据基本可以放弃了。如果只是零星几个,那就要对症下药。

2.1.1 均值填充——简单粗暴,但有用

均值填充,说白了就是用这列数据的平均值去填那个空。比如某台变压器的日负荷数据,缺失了中午12点的值,我就用前后几天的平均值补上。

我在项目中遇到过一个小问题:如果数据本身波动很大,均值填充会“拉平”曲线,导致后续分析失真。所以,均值填充只适合数据相对平稳的场景。

import pandas as pd
import numpy as np

# 示例数据:某变压器日负荷(kW)
data = {'时间': ['2024-01-01 00:00', '2024-01-01 01:00', '2024-01-01 02:00', '2024-01-01 03:00'],
        '负荷': [120, 115, None, 108]}
df = pd.DataFrame(data)

# 均值填充
mean_val = df['负荷'].mean()
df['负荷_填充'] = df['负荷'].fillna(mean_val)
print(df)
我的小技巧: 如果数据有周期性(比如电力负荷有日周期、周周期),可以按“同类时刻”计算均值。比如缺失周一上午10点的数据,就用其他周一上午10点的均值来填。这样更准。

2.1.2 插值法——更“聪明”的填充

插值法,就是根据已知数据点,拟合出一条曲线,然后估算缺失点的值。常用的有线性插值、多项式插值、样条插值。

嗯,这里要注意:插值法假设数据是连续的、平滑的。电力负荷数据通常满足这个条件,所以插值法很实用。

# 线性插值
df['负荷_插值'] = df['负荷'].interpolate(method='linear')
print(df)

我曾经用插值法处理过一个风电场的风速缺失数据。风速变化剧烈,线性插值效果不好,我换成了三次样条插值,效果立竿见影。所以,方法没有绝对好坏,得看数据特点。

2.1.3 删除法——最“狠”的方式

删除法,就是直接把有缺失的行或列删掉。简单、粗暴、有效,但代价是丢失信息。

我一般只在两种情况下用删除法:一是缺失比例极低(比如<1%),二是缺失值集中在某几个样本上,且这些样本本身就不重要。

避坑指南: 我曾经为了省事,直接删掉了一整列缺失数据,结果发现那列数据是后续分析的关键特征。后来我学乖了:删除前,一定要确认这列数据对你后续建模有没有用。
# 删除含有缺失值的行
df_clean = df.dropna()
print(df_clean)

2.2 异常值检测:揪出“捣乱分子”

异常值,就是那些明显偏离正常范围的数据点。比如某台变压器负荷突然飙到10000kW,而正常只有500kW——这要么是设备故障,要么是数据录入错误。

为什么异常值要处理?因为很多算法(比如线性回归、K-means聚类)对异常值非常敏感。一个异常点,就能把模型带偏。我见过一个案例,就因为一个异常值,整个预测模型的误差率从5%飙升到30%。

2.2.1 3σ原则——经典统计方法

3σ原则,也叫拉依达准则。它假设数据服从正态分布,那么99.7%的数据会落在均值±3个标准差范围内。超出这个范围,就认为是异常值。

说白了,就是“三倍标准差之外,都是可疑分子”。

# 3σ原则检测异常值
mean = df['负荷'].mean()
std = df['负荷'].std()
threshold = 3 * std

df['是否异常_3sigma'] = (np.abs(df['负荷'] - mean) > threshold)
print(df)
注意: 3σ原则对数据分布有要求。如果数据本身不是正态分布(比如偏态分布),这个方法会误判。我建议先用直方图或Q-Q图检查一下数据分布。

2.2.2 箱线图法——更“稳健”的选择

箱线图法不依赖数据分布,它基于四分位数。具体来说,它用Q1(下四分位数)和Q3(上四分位数)定义了一个“正常范围”:

  • 下界 = Q1 - 1.5 * IQR
  • 上界 = Q3 + 1.5 * IQR

其中IQR = Q3 - Q1。超出这个范围的数据点,就是异常值。

我个人更喜欢箱线图法,因为它对极端值不敏感,而且能处理非正态分布的数据。我在处理光伏发电数据时,经常用这个方法。

# 箱线图法检测异常值
Q1 = df['负荷'].quantile(0.25)
Q3 = df['负荷'].quantile(0.75)
IQR = Q3 - Q1

lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR

df['是否异常_boxplot'] = (df['负荷'] < lower_bound) | (df['负荷'] > upper_bound)
print(df)

2.3 实战对比:两种方法怎么选?

我整理了一个对比表,方便你快速决策:

方法 适用场景 优点 缺点
3σ原则 数据近似正态分布 计算简单,理论成熟 对非正态分布不友好
箱线图法 任意分布,尤其是偏态分布 稳健,不受极端值影响 对样本量有要求(一般>20)

你想想看,如果数据是电力负荷这种“有规律波动”的,我通常先用箱线图法。如果是传感器校准数据这种“理论上应该正态分布”的,3σ原则更合适。

2.4 处理流程:我的“三板斧”

最后,我分享一下自己的处理流程,算是“避坑指南”:

  1. 先看数据概览:用df.info()df.describe()快速了解缺失和异常情况。
  2. 缺失值处理:先判断缺失比例,再选方法。比例小用删除法,比例大用插值法或均值填充。
  3. 异常值检测:先用箱线图法“扫一遍”,再用3σ原则“复核”。如果两种方法都标记为异常,那基本可以确定是异常值。
  4. 处理异常值:可以删除,也可以用中位数或前后值替换。我个人习惯用中位数替换,因为中位数对异常值不敏感。
我的经验: 处理完数据后,一定要可视化对比一下。画个折线图,看看处理前后的曲线是否平滑。如果出现“断崖式”变化,说明处理方式可能有问题。

好了,这一章的内容就到这里。数据预处理虽然枯燥,但它是整个分析流程的基石。你想想看,地基没打好,房子能稳吗?下一章我们聊特征工程,到时候见。