第1章:数据读取——用Pandas搞定BMS数据文件

各位同行,咱们直接进入正题。

做储能系统数据分析,第一步就是读数据。这一步看似简单,但我在项目里见过太多人栽在这上面——文件路径写错、编码不对、时间格式乱掉……说白了,数据还没进门就卡住了。

今天我就带大家把「数据读取」这个基本功练扎实。咱们用Pandas,把CSV、Excel、BMS典型数据文件统统拿下。

1.1 准备工作:导入Pandas

先别急着读文件,把工具准备好。我个人习惯在代码开头这样写:

import pandas as pd
import numpy as np
import os

# 设置显示选项,方便查看数据
pd.set_option('display.max_columns', None)  # 显示所有列
pd.set_option('display.width', 1000)        # 显示宽度

嗯,这里有个小细节——display.max_columns设为None,能避免数据列太多时被截断。我在调试一个200多列的电芯数据时,就靠这个选项一眼发现了某列全是空值。

1.2 读取CSV文件

CSV是储能数据最常见的格式。BMS导出的历史数据,十有八九是CSV。基本用法:

# 最简单的读取
df = pd.read_csv('bms_data_20240101.csv')

# 实际项目中更常用的写法
df = pd.read_csv(
    'bms_data_20240101.csv',
    encoding='utf-8',          # 指定编码,避免乱码
    parse_dates=['timestamp'], # 自动解析时间列
    low_memory=False           # 避免大文件分块读取时的类型推断问题
)
⚠️ 避坑指南:我曾经因为没指定encoding,读出来的中文全是乱码。后来发现BMS厂家导出的文件,有的用utf-8,有的用gbk。我的经验是:先试utf-8,报错就换gbk

1.3 读取Excel文件

有些厂家喜欢用Excel存配置参数或日报数据。Excel文件可能包含多个sheet,读取时要注意:

# 读取第一个sheet
df = pd.read_excel('bms_config.xlsx')

# 读取指定sheet
df = pd.read_excel('bms_config.xlsx', sheet_name='参数设置')

# 读取所有sheet,返回一个字典
sheets_dict = pd.read_excel('bms_config.xlsx', sheet_name=None)

你想想看,如果不知道Excel里有几个sheet,直接用sheet_name=None就能全部读进来,然后遍历字典处理。这招我在处理厂家提供的「参数配置表」时屡试不爽。

1.4 读取BMS典型数据文件

BMS数据文件有个特点——列名往往很长,比如单体电压_01单体温度_01,而且时间戳格式五花八门。我给大家看一个真实案例:

# 读取BMS典型数据
df = pd.read_csv(
    'bms_typical_data.csv',
    encoding='utf-8',
    parse_dates=['采集时间'],
    dtype={
        '总电压': float,
        '总电流': float,
        'SOC': float
    }
)
💡 经验之谈:dtype指定数据类型,能避免Pandas把数字读成字符串。我遇到过SOC列因为混入了一个"N/A"字符,整列变成object类型,后续计算全崩了。

1.5 查看数据基本信息

数据读进来了,第一件事就是「看看它长什么样」。我一般三步走:

1.5.1 head()——看前几行

# 查看前5行
print(df.head())

# 查看前10行
print(df.head(10))

这一步能快速确认数据是否读对了,列名对不对,时间格式正不正常。

1.5.2 info()——看整体结构

print(df.info())

输出示例:

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 86400 entries, 0 to 86399
Data columns (total 12 columns):
 #   Column      Non-Null Count  Dtype         
---  ------      --------------  -----         
 0   采集时间      86400 non-null  datetime64[ns]
 1   总电压        86400 non-null  float64       
 2   总电流        86400 non-null  float64       
 3   SOC         86400 non-null  float64       
 4   单体电压_01   86400 non-null  float64       
 5   单体电压_02   86400 non-null  float64       
 6   单体温度_01   86400 non-null  float64       
 7   单体温度_02   86400 non-null  float64       
 8   绝缘电阻      86000 non-null  float64       
 9   状态标志      86400 non-null  int64         
 10  报警代码      85000 non-null  float64       
 11  备注         1200 non-null   object        
dtypes: datetime64[ns](1), float64(9), int64(1), object(1)
memory usage: 7.9 MB

info()是我最常用的函数。它能告诉我:

  • 有多少行、多少列
  • 每列的数据类型
  • 有没有缺失值(Non-Null Count)
  • 内存占用情况
🔍 注意看:上面例子中「绝缘电阻」只有86000条非空数据,比总行数86400少了400条。这说明有缺失值,后面清洗时就要处理。我一般看到这种差异,就会标记一下,后续做插值或删除。

1.5.3 describe()——看统计信息

print(df.describe())

输出示例:

指标 总电压 总电流 SOC 单体电压_01
count 86400.0 86400.0 86400.0 86400.0
mean 768.5 120.3 55.2 3.215
std 12.4 85.6 28.7 0.052
min 720.0 -200.0 0.0 2.800
25% 760.0 45.0 30.0 3.180
50% 770.0 110.0 55.0 3.215
75% 778.0 195.0 80.0 3.250
max 800.0 350.0 100.0 3.650

describe()能快速给出数值列的统计特征。我特别关注minmax——如果单体电压最小值低于2.8V,那电池可能已经过放了,需要立刻报警。

1.6 本章知识体系

下面这张图,是我梳理的数据读取核心流程:

数据读取核心流程 导入Pandas import pandas as pd 读取数据文件 CSV / Excel / BMS 查看基本信息 head / info / describe head() info() describe() 查看前几行数据 查看列数、类型、缺失值 查看统计特征 数据读取 → 快速检查 → 确认无误 → 进入清洗

1.7 实战小贴士

最后分享几个我踩过的坑:

  • 文件路径别用中文:我曾经把文件放在「桌面/储能数据」文件夹里,结果Pandas死活读不出来。后来改成英文路径,一次通过。
  • 大文件分块读:如果文件超过1GB,用chunksize参数分块读取,避免内存爆炸。
  • 时间列统一格式:BMS数据的时间戳可能是2024-01-01 00:00:00,也可能是2024/01/01 00:00:00。用parse_dates配合format参数,能保证解析正确。
📌 核心要点:数据读取不是简单的「读进来就完事」。head()看长相,info()看结构,describe()看统计——这三板斧抡完,你对数据就有了基本判断。后面清洗、分析才能有的放矢。

专注资料整理