3. 数据读取与初步探索:用pandas打开风电数据的大门
说实话,做风电数据清洗这几年,我见过太多人一上来就急着建模。结果呢?数据读进来全是乱码,或者类型不对,后面全白干。今天咱们就从最基础的开始——怎么把数据安安稳稳地读进来,再摸清它的脾气。
3.1 读取CSV文件:最常用的方式
风电数据最常见的格式就是CSV。为什么?因为SCADA系统、测风塔、CMS系统,导出数据基本都是CSV。我个人习惯用pandas.read_csv(),但有几个参数必须注意。
import pandas as pd
# 基础读取
df = pd.read_csv('wind_turbine_data.csv')
# 实际项目中我常用的方式
df = pd.read_csv(
'wind_turbine_data.csv',
encoding='utf-8', # 避免中文乱码
parse_dates=['timestamp'], # 时间列自动解析
low_memory=False # 大文件时避免类型推断错误
)
⚠️ 我曾经踩过的坑:有一次读取某风场的SCADA数据,发现时间列全是字符串。后来排查发现,数据里混了"2023/1/1"和"2023-01-01"两种格式。所以我现在都会加上
parse_dates参数,让pandas自动处理。
3.2 读取Excel文件:多表单的处理技巧
Excel文件在风电项目中也很常见,尤其是运维记录、故障日志这些。但Excel有个麻烦——一个文件里可能有好几个sheet。
# 读取单个sheet
df = pd.read_excel('fault_log.xlsx', sheet_name='2023年')
# 读取所有sheet
all_sheets = pd.read_excel('fault_log.xlsx', sheet_name=None)
# 返回的是一个字典,key是sheet名
# 指定列类型,避免数值被读成字符串
df = pd.read_excel(
'wind_data.xlsx',
dtype={'风速': float, '功率': float}
)
💡 小技巧:如果你发现Excel里的数字读进来变成了"2023/1/1 0:00"这种格式,八成是Excel自动格式化的锅。我一般会在读取时加上
dtype=str,然后再手动转换。
3.3 查看数据基本信息:head、info、describe
数据读进来了,第一件事是什么?别急着分析,先看看它长什么样。我通常三步走:
3.3.1 head()——瞄一眼数据长啥样
# 查看前5行
df.head()
# 查看前10行
df.head(10)
# 查看后5行
df.tail()
这一步主要是看:列名对不对?数据有没有明显异常?比如风速列出现负值,那肯定有问题。
3.3.2 info()——摸清数据类型和缺失情况
df.info()
输出结果大概长这样:
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 8760 entries, 0 to 8759
Data columns (total 8 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 timestamp 8760 non-null datetime64[ns]
1 风速 8745 non-null float64
2 功率 8730 non-null float64
3 桨距角 8700 non-null float64
4 转速 8750 non-null float64
5 温度 8760 non-null float64
6 风向 8740 non-null float64
7 状态码 8760 non-null int64
dtypes: datetime64[ns](1), float64(6), int64(1)
memory usage: 547.6 KB
这里我最关注两点:
- Non-Null Count:看看哪些列有缺失值。比如上面风速列有15个缺失,功率列有30个缺失。
- Dtype:数据类型对不对。时间列应该是datetime64,数值列应该是float64或int64。如果发现风速列是object(字符串),那就要小心了。
🔍 实际项目经验:有一次我发现功率列显示的是object类型,一查才发现数据里混了"---"这种占位符。这就是典型的脏数据,后面清洗时得处理掉。
3.3.3 describe()——快速了解数据分布
df.describe()
输出结果:
| 风速 | 功率 | 桨距角 | 转速 | 温度 | 风向 | |
|---|---|---|---|---|---|---|
| count | 8745.0 | 8730.0 | 8700.0 | 8750.0 | 8760.0 | 8740.0 |
| mean | 7.2 | 1500.0 | 5.3 | 12.1 | 25.0 | 180.0 |
| std | 4.1 | 800.0 | 8.2 | 3.5 | 5.0 | 90.0 |
| min | 0.0 | -50.0 | 0.0 | 0.0 | -10.0 | 0.0 |
| 25% | 3.5 | 800.0 | 0.0 | 9.0 | 21.0 | 90.0 |
| 50% | 7.0 | 1500.0 | 0.0 | 12.0 | 25.0 | 180.0 |
| 75% | 10.5 | 2200.0 | 8.0 | 15.0 | 29.0 | 270.0 |
| max | 30.0 | 2500.0 | 90.0 | 20.0 | 45.0 | 360.0 |
这里我一般会快速扫一眼:
- min和max:有没有明显不合理的数据?比如风速最大30m/s,对于某些机型可能已经切出了,但还在合理范围。但如果出现风速50m/s,那肯定是异常值。
- count:和总行数对比,看看缺失比例。比如总行数8760,风速只有8745,缺失了15条,占比0.17%,问题不大。
- mean和std:大致了解数据集中趋势和离散程度。比如功率均值1500kW,标准差800kW,说明波动挺大。
⚠️ 注意:describe()默认只统计数值列。如果你有分类列(比如状态码),可以用
df['状态码'].value_counts()来查看分布。
3.4 数据类型概览:为什么类型这么重要?
你想想看,如果风速列是字符串类型,你还能做加减乘除吗?肯定不行。所以数据类型检查是数据清洗的第一步。
# 查看每列的数据类型
df.dtypes
# 单独查看某一列
df['风速'].dtype
# 转换数据类型
df['风速'] = df['风速'].astype(float)
df['timestamp'] = pd.to_datetime(df['timestamp'])
常见的风电数据类型:
| 数据类型 | 示例列 | pandas类型 | 说明 |
|---|---|---|---|
| 时间 | timestamp | datetime64[ns] | 必须转换,否则无法做时间序列分析 |
| 连续数值 | 风速、功率、温度 | float64 | 最常用,注意是否有缺失值 |
| 离散数值 | 状态码、机舱编号 | int64 | 适合做分类统计 |
| 分类文本 | 风机型号、风场名称 | object | 可以转为category类型节省内存 |
💡 我的习惯:每次读取数据后,我会先跑一遍
df.dtypes,然后手动检查每一列的类型是否合理。如果发现异常,立即处理,绝不拖到后面。
3.5 本章知识体系
下面这张图总结了数据读取与初步探索的核心流程,你可以对照着检查自己的操作步骤:
嗯,到这里,数据读取和初步探索就讲完了。说白了,这一步就是给数据做个"体检"——看看它有没有"发烧"(异常值),有没有"缺胳膊少腿"(缺失值),有没有"穿错衣服"(类型错误)。
我个人觉得,这一步花的时间再多都不为过。因为后面所有的分析、建模、可视化,都建立在这个基础上。基础打好了,后面才能走得稳。
📌 核心要点回顾:
- 读取数据时注意编码、时间解析、类型指定
- head()看数据长什么样,info()看类型和缺失,describe()看分布
- 数据类型检查是数据清洗的第一步,发现问题立即处理