第3章:Python数据处理核心库:NumPy与Pandas基础
说实话,做遥测数据可视化,最绕不开的就是NumPy和Pandas。我刚开始接触遥测数据时,面对一堆时间戳和传感器数值,整个人是懵的。后来才发现,这两个库就是数据处理的两把瑞士军刀。今天咱们就把它们掰开揉碎了讲清楚。
本章核心脉络:NumPy负责底层数组运算,Pandas负责结构化数据处理。两者配合,能搞定90%的遥测数据清洗任务。
3.1 NumPy基础:数组操作与统计计算
NumPy的核心就是ndarray,也就是N维数组。你想想看,遥测数据里一个传感器每秒采集1000个点,一小时就是360万个数据点。用Python原生列表处理?那速度慢得让人抓狂。NumPy底层用C语言实现,运算速度能快几十倍。
3.1.1 创建数组
我个人习惯用np.array()把列表转成数组,或者用np.zeros()、np.ones()预分配空间。在遥测场景里,经常需要生成时间轴,这时候np.arange()和np.linspace()就特别好用。
import numpy as np
# 从列表创建
sensor_data = np.array([23.5, 24.1, 23.8, 24.3, 23.9])
print(sensor_data.dtype) # float64
# 生成时间轴:0到10秒,每0.01秒一个点
time_axis = np.arange(0, 10, 0.01)
print(f"时间点数量: {len(time_axis)}") # 1000个点
# 等间隔生成100个点
freq_axis = np.linspace(0, 100, 100)
我的经验:创建数组时一定要指定dtype。遥测数据里温度、压力这些浮点数用float32就够了,能省一半内存。我之前处理一个48小时的振动数据,没注意dtype,结果内存爆了。后来改成float32,问题就解决了。
3.1.2 数组索引与切片
NumPy的切片语法和Python列表很像,但功能更强。你可以用布尔索引来筛选数据,这在遥测数据里太常用了。
# 二维数组:3个传感器,每个采集5个点
data = np.array([
[23.5, 24.1, 23.8, 24.3, 23.9],
[45.2, 45.8, 44.9, 46.1, 45.5],
[12.3, 12.1, 12.5, 12.0, 12.4]
])
# 取第2个传感器的所有数据
sensor2 = data[1, :] # [45.2, 45.8, 44.9, 46.1, 45.5]
# 布尔索引:找出温度超过24.0的点
temp = data[0, :]
high_temp = temp[temp > 24.0] # [24.1, 24.3]
3.1.3 统计计算
NumPy提供了全套统计函数。我经常用np.mean()、np.std()来算均值和标准差,用np.percentile()来算分位数。这些在遥测数据异常检测里是基础操作。
# 模拟遥测数据:1000个温度值
np.random.seed(42)
temperatures = np.random.normal(loc=25.0, scale=2.0, size=1000)
# 基本统计量
mean_temp = np.mean(temperatures)
std_temp = np.std(temperatures)
max_temp = np.max(temperatures)
min_temp = np.min(temperatures)
# 分位数
q25, q50, q75 = np.percentile(temperatures, [25, 50, 75])
print(f"均值: {mean_temp:.2f}, 标准差: {std_temp:.2f}")
print(f"中位数: {q50:.2f}, 四分位距: {q75-q25:.2f}")
避坑指南:我曾经用np.mean()处理含NaN的数据,结果返回了NaN。后来才知道要加np.nanmean()。遥测数据经常有缺失值,记得用nan开头的函数。
3.2 Pandas基础:DataFrame与时间序列
如果说NumPy是数据处理的发动机,那Pandas就是驾驶舱。DataFrame这个数据结构,说白了就是带标签的表格。每一列有名字,每一行有索引,操作起来特别直观。
3.2.1 创建DataFrame
我习惯用字典来创建DataFrame,键就是列名。在遥测场景里,通常会把时间戳作为索引。
import pandas as pd
# 创建遥测数据表
data = {
'timestamp': ['2024-01-01 00:00:00', '2024-01-01 00:01:00',
'2024-01-01 00:02:00', '2024-01-01 00:03:00'],
'temperature': [23.5, 24.1, 23.8, 24.3],
'pressure': [1013.2, 1013.5, 1013.1, 1013.8],
'humidity': [45.2, 45.8, 44.9, 46.1]
}
df = pd.DataFrame(data)
# 把时间戳列转成datetime类型,并设为索引
df['timestamp'] = pd.to_datetime(df['timestamp'])
df.set_index('timestamp', inplace=True)
print(df.head())
3.2.2 时间序列处理
Pandas的时间序列功能非常强大。你可以用resample()重采样,用shift()做滞后计算。我记得有一次做振动数据分析,需要把毫秒级数据重采样到秒级,用resample('1S').mean()一行代码就搞定了。
# 生成高频时间序列
time_index = pd.date_range('2024-01-01', periods=1000, freq='100ms')
values = np.random.randn(1000).cumsum() + 20
ts = pd.Series(values, index=time_index)
# 重采样到秒级
ts_second = ts.resample('1S').mean()
# 计算滑动平均
ts_ma = ts.rolling(window=10).mean()
# 计算差分(变化率)
ts_diff = ts.diff()
我的习惯:处理时间序列时,我总会先检查时间索引是否连续。用df.index.is_monotonic_increasing检查,用df.asfreq()填充缺失的时间点。不然画出来的图会有断点,看起来很奇怪。
3.3 数据清洗实战
真实世界的遥测数据,从来都不是干干净净的。缺失值、异常值、重复值,什么妖魔鬼怪都有。数据清洗占了我工作中至少60%的时间。嗯,这里要注意,清洗做不好,后面分析全是白费。
3.3.1 缺失值处理
遥测数据缺失的原因很多:传感器故障、网络丢包、存储异常。处理方式有三种:删除、填充、插值。我个人偏好插值,因为它能保留数据趋势。
# 模拟含缺失值的遥测数据
df_clean = pd.DataFrame({
'time': pd.date_range('2024-01-01', periods=10, freq='1H'),
'value': [23.5, 24.1, None, 24.3, None, 23.9, 24.2, None, 24.0, 23.8]
})
df_clean.set_index('time', inplace=True)
# 方法1:删除缺失值
df_drop = df_clean.dropna()
# 方法2:向前填充(用上一个值填充)
df_ffill = df_clean.fillna(method='ffill')
# 方法3:线性插值(推荐)
df_interp = df_clean.interpolate(method='linear')
print("插值结果:")
print(df_interp)
注意:如果连续缺失超过3个点,插值结果可能不准确。我曾经处理一个温度传感器数据,连续缺失了10个点,用线性插值后画出的曲线完全失真。后来改用limit=3参数,超过3个缺失就直接标记为无效。
3.3.2 异常值检测
异常值检测我常用两种方法:3σ原则和IQR(四分位距)法。3σ适合正态分布的数据,IQR更稳健,不受极端值影响。
# 模拟含异常值的数据
np.random.seed(42)
data = np.random.normal(25, 2, 100)
data[50] = 35.0 # 人为加入异常值
data[80] = 15.0
# 方法1:3σ原则
mean = np.mean(data)
std = np.std(data)
outliers_3sigma = data[(data < mean - 3*std) | (data > mean + 3*std)]
print(f"3σ检测到异常值: {outliers_3sigma}")
# 方法2:IQR法
q1 = np.percentile(data, 25)
q3 = np.percentile(data, 75)
iqr = q3 - q1
lower_bound = q1 - 1.5 * iqr
upper_bound = q3 + 1.5 * iqr
outliers_iqr = data[(data < lower_bound) | (data > upper_bound)]
print(f"IQR检测到异常值: {outliers_iqr}")
3.3.3 数据规整
数据规整包括去重、类型转换、格式统一。遥测数据里经常遇到时间格式不统一的问题,有的用ISO格式,有的用时间戳。我习惯统一转成datetime类型。
# 数据规整示例
df_raw = pd.DataFrame({
'time': ['2024-01-01 00:00:00', '2024-01-01 00:00:00', # 重复
'2024-01-01 00:01:00', '2024-01-01 00:02:00'],
'temp': ['23.5', '23.5', '24.1', '23.8'], # 字符串类型
'pressure': [1013.2, 1013.2, 1013.5, None] # 缺失值
})
# 去重
df_dedup = df_raw.drop_duplicates()
# 类型转换
df_dedup['temp'] = pd.to_numeric(df_dedup['temp'])
# 时间统一
df_dedup['time'] = pd.to_datetime(df_dedup['time'])
# 缺失值填充
df_dedup['pressure'].fillna(method='ffill', inplace=True)
print("清洗后的数据:")
print(df_dedup)
实战总结:数据清洗没有银弹。我的经验是:先了解数据来源和采集方式,再决定清洗策略。比如温度传感器,变化缓慢,用向前填充没问题;但振动传感器,变化剧烈,最好用插值或直接丢弃缺失段。
好了,NumPy和Pandas的基础就讲到这里。这两个库是遥测数据处理的基石,多练练就能找到感觉。下一节我们会用这些工具,真正动手处理一份真实的遥测数据集。
可可精品资料库