第4章 数据源接入(上):从CSV/Excel文件读取设备数据
大家好,我是你们的老朋友。今天咱们聊聊数据源接入这件事。
做可视化看板,第一步就是搞定数据。没有数据,再炫酷的图表都是空中楼阁。我个人习惯把数据接入分成两步:先读进来,再洗干净。今天咱们就先把「读进来」这件事讲透。
核心要点:用Pandas读取CSV和Excel文件,是设备数据接入最基础、最常用的方式。掌握它,你就拿到了数据处理的入场券。
4.1 为什么选择Pandas?
你可能会问:Python里读取文件的方式那么多,为什么非要用Pandas?
嗯,这个问题我当年也想过。直到我在项目中遇到一个场景:一个设备日志文件有50万行,用普通文件读取方式,光解析就要花掉好几分钟。换成Pandas的read_csv(),几秒钟搞定。说白了,Pandas就是为表格数据而生的。
我在项目中遇到过不少同事,明明数据量不大,却硬要用open()加循环去解析CSV。结果代码写了一长串,还容易出错。其实用Pandas,一行代码就能搞定。
| 对比项 | 普通文件读取 | Pandas读取 |
|---|---|---|
| 代码量 | 10-20行 | 1-2行 |
| 处理速度 | 慢(逐行解析) | 快(底层C优化) |
| 数据类型推断 | 需要手动处理 | 自动推断 |
| 缺失值处理 | 需要手动判断 | 自动识别NaN |
4.2 读取CSV文件:最常用的方式
CSV文件是设备数据最常见的存储格式。传感器数据、日志记录、设备状态,很多都存成CSV。
先看一个最简单的例子:
import pandas as pd
# 读取CSV文件
df = pd.read_csv('device_data.csv')
print(df.head()) # 查看前5行
就这么简单?对,就这么简单。但实际项目中,CSV文件往往没那么规整。我曾经遇到过一个设备数据文件,编码格式是GBK,字段分隔符是分号,还带表头。如果直接用默认参数,读出来全是乱码。
这时候就需要调整参数了:
# 处理常见问题的读取方式
df = pd.read_csv(
'device_data.csv',
encoding='gbk', # 指定编码
sep=';', # 指定分隔符
header=0, # 第一行作为列名
skiprows=[1, 3], # 跳过第2行和第4行(索引从0开始)
na_values=['NA', 'N/A', 'NULL'] # 指定哪些值视为缺失
)
小技巧:如果你不确定文件编码,可以用chardet库自动检测。我习惯先检测再读取,避免反复试错。
4.3 读取Excel文件:更复杂的场景
Excel文件比CSV复杂一些。一个Excel文件可能包含多个工作表,每个表里还有合并单元格、不同数据类型等。
读取Excel的基本方式:
# 读取Excel文件
df = pd.read_excel('device_data.xlsx', sheet_name='设备数据')
但实际项目中,我遇到过更头疼的情况。有一次,一个设备供应商发来的Excel文件,里面居然有3个工作表,每个表的结构都不一样。第一个表是设备基本信息,第二个表是运行数据,第三个表是维修记录。
这时候就需要分别读取:
# 读取多个工作表
df_info = pd.read_excel('device_data.xlsx', sheet_name='基本信息')
df_runtime = pd.read_excel('device_data.xlsx', sheet_name='运行数据')
df_maintenance = pd.read_excel('device_data.xlsx', sheet_name='维修记录')
# 或者一次性读取所有工作表
all_sheets = pd.read_excel('device_data.xlsx', sheet_name=None)
# all_sheets是一个字典,键是工作表名,值是DataFrame
注意:读取Excel需要安装openpyxl或xlrd库。我推荐用openpyxl,它对.xlsx格式支持更好。安装命令:pip install openpyxl
4.4 数据清洗与预处理:让数据变得可用
数据读进来了,但往往不能直接用。你想想看,设备数据里经常有缺失值、重复值、异常值。不清洗的话,做出来的图表全是错的。
我曾经接手过一个项目,前同事做的看板,温度曲线总是莫名其妙地跳变。查了半天,发现是原始数据里混入了几个9999的异常值。这就是数据清洗没做好的后果。
下面是我常用的清洗步骤:
4.4.1 处理缺失值
# 查看缺失值情况
print(df.isnull().sum())
# 方法1:删除包含缺失值的行
df_clean = df.dropna()
# 方法2:用均值填充
df['温度'].fillna(df['温度'].mean(), inplace=True)
# 方法3:用前一个值填充(适用于时间序列数据)
df['温度'].fillna(method='ffill', inplace=True)
4.4.2 处理重复值
# 查看重复行
print(df.duplicated().sum())
# 删除重复行
df_clean = df.drop_duplicates()
# 按指定列判断重复
df_clean = df.drop_duplicates(subset=['设备ID', '时间戳'])
4.4.3 处理异常值
# 使用Z-score方法检测异常值
from scipy import stats
z_scores = stats.zscore(df['温度'])
abs_z_scores = np.abs(z_scores)
filtered_entries = (abs_z_scores < 3) # 保留Z-score小于3的数据
df_clean = df[filtered_entries]
# 或者用IQR方法
Q1 = df['温度'].quantile(0.25)
Q3 = df['温度'].quantile(0.75)
IQR = Q3 - Q1
df_clean = df[(df['温度'] >= Q1 - 1.5*IQR) & (df['温度'] <= Q3 + 1.5*IQR)]
经验之谈:处理异常值时,不要一刀切。我建议先可视化看看数据分布,再决定阈值。有时候看似异常的值,其实是设备在特殊工况下的正常数据。
4.5 实战案例:设备温度数据清洗
咱们来个完整的例子。假设你拿到了一份设备温度数据,包含设备ID、时间戳、温度值三列。数据里有缺失值、重复行,还有几个明显异常的温度值。
import pandas as pd
import numpy as np
# 1. 读取数据
df = pd.read_csv('device_temperature.csv', encoding='utf-8')
# 2. 查看数据概况
print("数据形状:", df.shape)
print("数据类型:\n", df.dtypes)
print("缺失值统计:\n", df.isnull().sum())
# 3. 清洗数据
# 3.1 删除重复行
df = df.drop_duplicates()
# 3.2 处理缺失值(用前一个有效值填充)
df['温度'] = df['温度'].fillna(method='ffill')
# 3.3 处理异常值(温度正常范围:-20°C ~ 80°C)
df = df[(df['温度'] >= -20) & (df['温度'] <= 80)]
# 4. 转换时间戳为datetime类型
df['时间戳'] = pd.to_datetime(df['时间戳'])
# 5. 按时间排序
df = df.sort_values('时间戳')
print("清洗完成,剩余数据量:", len(df))
print(df.head())
关键点:数据清洗的顺序很重要。我习惯先删重复,再处理缺失,最后处理异常。这样能避免重复操作带来的干扰。
4.6 本章知识体系
下面这张图,是我自己总结的数据接入与清洗的完整流程。你可以把它当作一个检查清单,每次做数据接入时对照着来。
这张图把整个流程串起来了。从数据读取开始,经过预览、清洗、转换,最后得到干净可用的数据。每一步都有对应的Pandas方法,你照着做就行。
我的习惯:每次清洗完数据,我都会保存一份清洗后的副本。这样万一后续发现清洗逻辑有问题,还能回溯到原始数据重新处理。
好了,今天的内容就到这里。数据接入是可视化看板的基础,把这一步做扎实了,后面的图表制作才能事半功倍。记住,好的数据质量,胜过一百个炫酷的图表效果。
公众号:蓝海资料掘金营,微信deep3321