第4章:CSV数据读取与初步探索
各位同学,欢迎来到实战环节。从这一章开始,我们就要真刀真枪地跟风机SCADA数据打交道了。
我个人习惯,拿到任何数据源,第一件事不是建模,也不是画图。而是先把它读进来,然后好好“打量”一番。说白了,就像你拿到一本新书,先看看封面、目录、厚度,心里有个底。数据分析也是这个理儿。
4.1 用Pandas读取CSV文件
风机SCADA数据最常见的存储格式就是CSV。为什么?因为它简单、通用,几乎所有系统都能导出。我见过有些风场用Excel存数据,那真是噩梦——文件大一点就卡死,还容易损坏。
读取CSV,Pandas提供了read_csv()函数。这是最基础,也是最核心的一步。
import pandas as pd
# 读取SCADA数据
df = pd.read_csv('wind_turbine_scada.csv')
嗯,就这么一行。但这里有个坑——编码问题。我曾经在某个风场项目里,读一个国产机组的CSV文件,直接报错。后来发现是编码格式不是默认的UTF-8,而是GBK。所以,我建议你养成习惯,遇到中文数据,加上encoding='gbk'或encoding='utf-8'参数。
chardet库自动检测。
# 带编码参数的读取方式
df = pd.read_csv('wind_turbine_scada.csv', encoding='gbk')
4.2 快速预览数据:head()方法
数据读进来了,第一件事是什么?看一眼长什么样。用head()方法,默认显示前5行。
# 查看前5行数据
df.head()
你会看到类似这样的表格:
| 时间戳 | 风速(m/s) | 有功功率(kW) | 桨距角(°) | 发电机转速(rpm) |
|---|---|---|---|---|
| 2024-01-01 00:00:00 | 8.5 | 1500.2 | 12.3 | 1750 |
| 2024-01-01 00:10:00 | 9.1 | 1620.5 | 11.8 | 1780 |
| 2024-01-01 00:20:00 | 7.8 | 1380.0 | 13.5 | 1700 |
看到这个,你心里就有数了:数据是10分钟一条的时序记录,包含风速、功率、桨距角、转速等关键参数。如果数据量很大,你也可以指定行数,比如df.head(10)看前10行。
4.3 数据概览:info()方法
head()只能看数据内容,但数据的“体质”怎么样?有没有空值?每列是什么类型?这时候就要用info()了。
# 查看数据基本信息
df.info()
输出结果大概长这样:
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 52560 entries, 0 to 52559
Data columns (total 8 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 时间戳 52560 non-null object
1 风速(m/s) 52560 non-null float64
2 有功功率(kW) 52560 non-null float64
3 桨距角(°) 52560 non-null float64
4 发电机转速(rpm) 52560 non-null float64
5 机舱温度(℃) 52300 non-null float64
6 齿轮箱油温(℃) 52180 non-null float64
7 状态码 52560 non-null int64
dtypes: float64(6), int64(1), object(1)
memory usage: 3.2 MB
这里信息量很大,我带你逐条看:
- 行数:52560行,正好是一年(365天×24小时×6条/小时)的10分钟数据。
- 列数:8列,包含时间、风速、功率等。
- 非空计数:注意看“机舱温度”和“齿轮箱油温”这两列,非空值少于总行数。这说明什么?有缺失值。
- 数据类型:大部分是float64(浮点数),状态码是int64(整数),时间戳是object(字符串)。
parse_dates=['时间戳']参数。
4.4 统计描述:describe()方法
info()告诉你数据“有没有”,describe()则告诉你数据“好不好”。它会自动计算数值型列的统计量。
# 查看数值列的统计描述
df.describe()
输出结果:
| 统计量 | 风速(m/s) | 有功功率(kW) | 桨距角(°) | 发电机转速(rpm) |
|---|---|---|---|---|
| count | 52560.0 | 52560.0 | 52560.0 | 52560.0 |
| mean | 7.2 | 1200.5 | 10.8 | 1650.0 |
| std | 3.5 | 600.2 | 5.2 | 200.0 |
| min | 0.0 | -50.0 | 0.0 | 0.0 |
| 25% | 4.5 | 650.0 | 6.5 | 1500.0 |
| 50% | 7.0 | 1150.0 | 10.0 | 1680.0 |
| 75% | 9.8 | 1750.0 | 14.5 | 1820.0 |
| max | 25.0 | 2000.0 | 90.0 | 2000.0 |
这里有几个点值得关注:
- 有功功率最小值是-50kW:这不对劲。风机正常发电不会为负值,除非是停机状态下的厂用电消耗。这说明数据里混入了异常值。
- 桨距角最大值90°:正常运行时桨距角一般在0-30°之间,90°通常是停机或故障状态。
- 风速最大值25m/s:这已经接近切出风速了,说明数据覆盖了极端工况。
你看,光是一个describe(),就能发现这么多线索。我在项目中就遇到过,某风场功率曲线异常,一查describe()发现风速数据有大量0值,原来是传感器冻住了。
4.5 数据维度与缺失值概览
最后,我们来看看数据的“身材”和“健康状况”。
# 查看数据维度(行数,列数)
print(f"数据维度:{df.shape}")
# 查看每列缺失值数量
print(f"缺失值统计:\n{df.isnull().sum()}")
输出:
数据维度:(52560, 8)
缺失值统计:
时间戳 0
风速(m/s) 0
有功功率(kW) 0
桨距角(°) 0
发电机转速(rpm) 0
机舱温度(℃) 260
齿轮箱油温(℃) 380
状态码 0
dtype: int64
嗯,果然。机舱温度缺了260条,齿轮箱油温缺了380条。这些缺失值怎么处理?是直接删除,还是填充?这取决于缺失比例和数据的重要性。260/52560 ≈ 0.5%,比例很小,删除影响不大。但如果是关键参数,我建议用前后均值填充。
- 缺失率 < 1%:直接删除该行
- 缺失率 1%-5%:用均值/中位数填充
- 缺失率 > 5%:需要深入分析缺失原因,可能涉及传感器故障
本章知识体系
下面这张图,帮你梳理本章的核心逻辑:
这张图把本章的五个步骤串起来了。从读取CSV开始,到预览、概览、统计描述,最后检查维度与缺失值。每一步都有明确的目的,环环相扣。
好了,这一章的内容就到这里。记住,拿到数据别急着分析,先花5分钟做一遍这个“体检”。你会发现,很多问题在第一步就能暴露出来,省得后面走弯路。
公众号:蓝海资料掘金营,微信deep3321