数据探索与可视化:先看看你的数据长什么样

拿到风电数据的第一件事是什么?不是急着调模型,而是先跟数据「打个招呼」。我个人的习惯是,先花半小时把数据摸一遍,看看它有没有「生病」。这步做好了,后面能省下大把的调试时间。

说白了,数据探索就像医生给病人做体检。你得先知道血压、心率、体温这些指标,才能判断哪里出了问题。风电数据也一样,传感器采集来的信号,可能带着噪声、缺失值,甚至还有异常点。我们这节课就来干这件事。

1. 加载CSV数据:第一步,把数据请进来

Python里加载CSV,最常用的就是pandas。我一般这么写:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

# 加载风电数据
df = pd.read_csv('wind_turbine_data.csv', parse_dates=['timestamp'])
print('数据加载完成,形状为:', df.shape)

这里有个小细节——parse_dates参数。我遇到过不少同学,数据加载完才发现时间列是字符串类型,后面处理起来特别麻烦。所以,加载时就指定时间列,省得后面再转换。

我的经验:如果CSV文件很大,可以加个nrows=1000先预览前1000行,确认格式没问题再全量加载。我曾经一次加载了5GB的数据,结果发现列名对不上,白白浪费了半小时。

2. describe() 和 info():快速摸清数据底细

加载完数据,我习惯先跑两个函数:

# 查看数据基本信息
print(df.info())

# 查看数值型列的统计摘要
print(df.describe())

info()会告诉你每列的数据类型、非空值数量。嗯,这里要注意——如果某列显示object类型,但实际应该是数值,那就要检查是不是混入了字符串(比如「N/A」或「-」)。

describe()则给出均值、标准差、四分位数等统计量。我特别关注minmax这两行。举个例子,风速传感器的正常范围是0~30m/s,如果max显示100,那肯定有问题。

指标 风速(m/s) 功率(kW) 转速(rpm)
count 10000 10000 10000
mean 8.5 1500 12.3
std 4.2 800 3.1
min 0.0 -50 0.0
max 35.0 2500 20.0

你看,功率的min是-50,这明显不合理——功率不可能是负值。这就是异常值的信号。

3. 缺失值可视化:找到数据里的「黑洞」

风电数据里,缺失值很常见。传感器故障、通信中断、维护停机,都可能导致数据缺失。我习惯用热力图来可视化缺失情况:

import missingno as msno

# 缺失值矩阵图
msno.matrix(df)
plt.title('缺失值分布矩阵')
plt.show()

# 缺失值柱状图
msno.bar(df)
plt.title('各列缺失值数量')
plt.show()

为什么要可视化?因为光看数字不够直观。你想想看,如果缺失值集中在某段时间,那可能是那个时间段传感器出了问题。如果缺失值随机分布,那可能是偶发性的通信丢包。

避坑指南:我曾经处理过一批数据,缺失率只有5%,看起来不多。但画出来才发现,缺失值全部集中在凌晨2点到4点——原来是那个时段的采集程序有bug。如果直接填充均值,就会把这种规律性缺失给掩盖掉。

4. 箱线图与异常值初探:揪出「捣乱分子」

箱线图是发现异常值的利器。它用四分位数来定义正常范围,超出1.5倍IQR(四分位距)的点就被标记为异常值。

# 绘制风速的箱线图
plt.figure(figsize=(10, 6))
sns.boxplot(x=df['wind_speed'])
plt.title('风速箱线图')
plt.show()

# 同时绘制多个特征
plt.figure(figsize=(12, 6))
sns.boxplot(data=df[['wind_speed', 'power', 'rotor_speed']])
plt.title('多个特征的箱线图对比')
plt.show()

箱线图能告诉你三件事:

  • 数据的集中趋势:中位数在哪里
  • 数据的离散程度:箱体有多宽
  • 异常值的位置:那些孤零零的小圆点

举个例子,风速的箱线图显示上边缘是25m/s,但有几个点跑到了40m/s。这些点可能是极端天气,也可能是传感器故障。怎么区分?我会结合时间戳去看——如果这些点发生在台风天,那可能是真实数据;如果发生在风和日丽的下午,那八成是传感器抽风了。

注意:箱线图标记的「异常值」只是统计学意义上的离群点,不一定是真正的故障数据。别一看到异常值就删掉,先问问自己:这个值在物理上是否可能?

5. 知识体系总览

下面这张图,把数据探索的核心流程串起来了:

数据探索与可视化知识体系 加载CSV数据 pd.read_csv() 基本信息查看 info() + describe() 缺失值可视化 missingno库 异常值 箱线图 数据类型检查 数值 vs 字符串 时间格式转换 统计分布检查 均值/中位数/标准差 min/max合理性 缺失模式分析 随机缺失 vs 规律缺失 缺失率阈值判断 目标:理解数据质量,为异常检测做准备

这张图展示了数据探索的四个核心步骤,以及每个步骤需要关注的关键点。从加载数据开始,到基本信息查看,再到缺失值和异常值的识别,每一步都在为后续的异常检测打基础。

6. 实战小贴士:把这些代码串起来

最后,我分享一个我常用的「数据体检」模板。每次拿到新数据,我都会跑一遍:

def data_health_check(df):
    """数据健康检查函数"""
    print("="*50)
    print("1. 数据形状:", df.shape)
    print("="*50)
    
    print("\n2. 列信息:")
    print(df.info())
    
    print("\n3. 统计摘要:")
    print(df.describe())
    
    print("\n4. 缺失值统计:")
    missing = df.isnull().sum()
    missing_pct = (missing / len(df)) * 100
    missing_df = pd.DataFrame({'缺失数量': missing, '缺失比例(%)': missing_pct})
    print(missing_df[missing_df['缺失数量'] > 0])
    
    # 绘制箱线图
    numeric_cols = df.select_dtypes(include=[np.number]).columns[:6]
    fig, axes = plt.subplots(2, 3, figsize=(15, 8))
    axes = axes.flatten()
    for i, col in enumerate(numeric_cols):
        sns.boxplot(y=df[col], ax=axes[i])
        axes[i].set_title(f'{col} 箱线图')
    plt.tight_layout()
    plt.show()
    
    return missing_df

# 使用示例
missing_info = data_health_check(df)

这个函数会一口气输出数据的基本信息、统计摘要、缺失情况,还会自动绘制箱线图。我建议你把它保存下来,以后每个项目都能用。

核心要点回顾:
  • 加载数据时指定时间列,避免后续转换麻烦
  • info()和describe()是快速了解数据的「体检报告」
  • 缺失值可视化能发现规律性缺失,比单纯看数字更有价值
  • 箱线图的异常值只是统计意义上的离群点,需要结合物理意义判断

数据探索这一步,说白了就是跟数据「混个脸熟」。你花的时间越多,后面建模就越顺。别急着跳过去,慢慢来,比较快。


专注资料整理