CWRU轴承数据集:工业AI故障诊断的Python实战指南

📅 2026/8/27 6:53:26
CWRU轴承数据集:工业AI故障诊断的Python实战指南
简介在工业设备预测性维护和故障诊断领域振动信号分析是核心技术之一。其原理在于设备运行状态的变化会反映在振动信号的时域、频域及时频域特征中。通过特征工程提取这些关键指标能够构建有效的智能诊断模型从而实现设备健康状态的自动化监测与预警大幅降低非计划停机风险。CWRU轴承数据集作为该领域的基准提供了标准化的实验数据是验证算法性能、进行特征提取和模型训练的宝贵资源。本文结合Python实战详细解析了如何利用该数据集进行从数据加载、特征工程到模型构建的全流程开发并深入探讨了跨负载诊断等实际挑战为工业AI研究者提供了即拿即用的工具与避坑指南。1. 项目概述一份工业AI研究者的“宝藏”数据集如果你正在或即将踏入工业设备故障诊断、预测性维护或者机械信号处理这个领域那么“凯斯西储大学(CWRU)轴承数据集”这个名字你大概率已经听过无数次了。它几乎是这个领域的“MNIST”或“ImageNet”是无数论文、算法模型和学术研究的起点与试金石。我第一次接触这个数据集是在做一个电机早期故障预警的课题时导师甩给我一个链接说“去把这个数据下下来跑一遍你的算法行不行它说了算。” 从那时起我就和这份数据结下了不解之缘。简单来说CWRU轴承数据集是一套在严格控制的实验室环境下采集的滚动轴承全生命周期振动信号数据。它记录了轴承从健康状态到人为植入单一故障包括内圈、外圈、滚动体故障再到故障逐渐恶化的整个过程。数据以高采样频率12kHz或48kHz采集包含了驱动端和风扇端的加速度振动信号是进行故障特征提取、模式识别和智能诊断算法开发的绝佳素材。这份数据的核心价值在于其“标准性”和“纯净度”。在工业现场我们采集的信号往往混杂着强烈的背景噪声、工况波动以及多种设备的耦合干扰想要验证一个特征提取算法或分类模型是否真的有效非常困难。CWRU数据集提供了一个近乎理想的“对照实验”环境让你能排除绝大多数干扰专注于算法本身性能的验证与提升。无论是做传统的时频域分析、小波变换还是搞现在火热的深度学习用一维CNN处理振动信号简直是经典案例这个数据集都是绕不开的第一站。所以无论你是高校里做相关研究的学生、老师还是工业界正在探索设备智能运维的工程师手头备一份整理好的CWRU数据集和能快速上手的Python工具都能极大提升你的工作效率。今天我就把自己多年来使用和整理这份数据集的经验、踩过的坑以及一套即拿即用的Python程序打包分享出来希望能帮你快速跨过“找数据、下数据、处理数据”这道繁琐的门槛直接进入核心的算法研究环节。2. 数据集深度解析不只是文件更是实验范本很多人拿到CWRU数据集看到一堆以“.mat”结尾的文件和复杂的文件夹结构就头疼觉得这只是一堆冷冰冰的数字。但在我看来理解这个数据集背后的实验设计比数据本身更重要。只有明白了数据是怎么来的你才能正确地使用它避免得出错误的结论。2.1 实验台架与数据采集的“上帝视角”CWRU的实验台架是一个经典的“电机-扭矩传感器-测功机”结构。电机2马力约1.5kW通过一根转轴驱动一个测功机轴承就安装在电机的驱动端和风扇端。故障是通过电火花加工技术在轴承上精确制造的单一故障点包括内圈故障、外圈故障和滚动体故障每种故障的直径又有0.007英寸、0.014英寸和0.021英寸等不同尺寸模拟了故障从轻微到严重的发展过程。这里有几个关键细节直接决定了你后续处理数据的方式采样频率与数据长度数据集主要提供12kHz和48kHz两种采样频率的数据。12kHz的数据对于轴承故障特征频率通常几百Hz来说已经足够且文件更小适合快速验证算法。48kHz的数据则包含了更丰富的高频信息适合研究更精细的特征或高频共振带。每个数据文件通常包含120,000个点对应10秒12kHz或2.5秒48kHz的时长。负载工况数据是在四种不同的电机负载0, 1, 2, 3马力下采集的。这是这个数据集最宝贵的部分之一它模拟了设备在不同工作负荷下的状态。一个鲁棒的故障诊断算法应该能在不同负载下都保持较高的识别准确率。如果你只用了0负载的数据做训练然后去测试3负载的数据效果暴跌那就说明你的算法特征可能对负载变化敏感需要改进。传感器位置振动加速度传感器分别安装在驱动端和风扇端的轴承座壳体上。通常驱动端的数据更受关注因为故障轴承就安装在此处信号更直接。风扇端的数据有时作为辅助或用于研究信号传递特性。注意下载数据时务必注意区分“驱动端故障”和“风扇端故障”的数据文件夹。曾经有同行误用了风扇端的数据来验证驱动端故障的诊断模型结果特征对不上调试了半天才发现是数据源弄错了。2.2 数据文件结构与命名“密码”原始数据集网站的文件结构是按故障类型、故障尺寸、负载和采样频率分层存放的。文件名本身就像一串密码包含了关键信息。例如一个名为105.mat的文件可能代表“驱动端轴承12点钟方向故障0.007英寸故障直径0负载”下的数据。为了降低使用门槛我提供的整理版程序会帮你自动解析这些信息并统一命名。但了解其原始逻辑有助于你在遇到特殊情况时能手动排查。我的整理思路是创建一个DataFrame或字典将每个文件路径与清晰的标签对应起来比如label:Normal正常,IF_007内圈故障0.007英寸,OF_014外圈故障0.014英寸,BF_021滚动体故障0.021英寸等。load:0,1,2,3(马力)。rpm: 根据负载对应的电机转速约1797, 1772, 1750, 1730 RPM这个信息对计算故障特征频率至关重要。position:DE驱动端,FE风扇端。2.3 为什么说它是“标准答案”在工业AI领域算法性能的横向对比一直是个难题。大家用的数据不一样评价指标也可能有细微差别导致论文里的“SOTA”当前最优可能水分很大。CWRU数据集之所以成为事实上的标准就是因为大家约定俗成地用它来测试和对比算法。当你说“我的模型在CWRU上达到了99.5%的准确率”时同行立刻就能对你的工作有一个基本的定位。但这把“双刃剑”也带来了一个问题针对这个数据集的“过拟合”。有些研究设计了非常复杂的网络结构在CWRU上刷到了接近100%的准确率但模型可能只记住了这个特定实验台架、特定采样设置下的某些噪声或模式换到其他设备或现场数据上就失效了。因此我的建议是把CWRU当作一个强大的“训练场”和“验证基准”而不是终极目标。在这里验证你特征工程和模型架构的基本有效性然后一定要寻找其他数据集或真实数据去测试其泛化能力。3. Python工具箱实战从零到一玩转CWRU数据光说不练假把式。接下来我将详细介绍配套Python程序的核心模块和使用方法。这套工具的目标是让你在5分钟内就能把原始的.mat文件变成可以直接喂给机器学习模型的、规整的特征矩阵和标签向量。3.1 环境搭建与依赖安装工欲善其事必先利其器。首先确保你的Python环境建议3.8及以上版本已经就绪。核心依赖库如下# 在终端或Anaconda Prompt中执行 pip install numpy scipy matplotlib pandas scikit-learn # 如果进行深度学习还需要 pip install torch tensorflow # 根据你的偏好二选一或都安装 # 强烈建议用于信号处理的库 pip install pywt # 小波变换 pip install librosa # 音频/信号处理功能强大 pip install antropy # 计算熵特征非常有用实操心得我强烈推荐使用conda或venv创建独立的虚拟环境来管理项目依赖。特别是scipy和pywt这类涉及底层编译的库虚拟环境能避免版本冲突。曾经在服务器上因为系统Python的scipy版本太老导致.mat文件读取失败折腾了半天。3.2 核心模块拆解数据加载与预处理我的程序包通常包含以下几个核心.py文件config.py: 存放所有路径、故障类型映射、采样频率等常量。data_loader.py: 负责遍历文件夹加载.mat文件并提取信号数据。feature_extractor.py: 特征工程的“主战场”包含时域、频域、时频域多种特征计算函数。utils.py: 一些工具函数如绘图、数据分割、标准化等。main_demo.py: 一个完整的示例脚本展示从加载数据到训练简单分类器的全流程。让我们深入data_loader.py的关键部分import os import scipy.io as sio import numpy as np import pandas as pd from config import DATA_PATH, FAULT_MAPPING, SAMPLE_FREQ class CWRULoader: def __init__(self, base_pathDATA_PATH): self.base_path base_path self.file_paths [] self.labels [] self.load_conditions [] def traverse_and_load(self): 遍历数据目录构建文件路径和标签列表 for fault_dir in os.listdir(self.base_path): fault_path os.path.join(self.base_path, fault_dir) if not os.path.isdir(fault_path): continue # 解析故障类型这里需要根据你的文件夹命名规则来写逻辑 if Normal in fault_dir: label Normal elif InnerRace in fault_dir: label IF fault_dir.split(_)[-1] # 例如 IF_007 # ... 类似地解析外圈和滚动体故障 for file_name in os.listdir(fault_path): if file_name.endswith(.mat): file_path os.path.join(fault_path, file_name) self.file_paths.append(file_path) self.labels.append(label) # 可以从文件名中进一步解析负载信息如 _0.mat 代表0负载 load self._parse_load_from_filename(file_name) self.load_conditions.append(load) def load_single_file(self, file_path): 加载单个.mat文件CWRU数据中信号通常保存在以变量名如 DE 或 FE 下 mat_data sio.loadmat(file_path) # 关键点需要查看一下.mat文件里具体的变量名常见的是 X***_DE_time 之类的 # 这里假设我们取驱动端加速度信号变量名为 DE vibration_signal mat_data[DE].flatten() # 确保是一维数组 return vibration_signal def _parse_load_from_filename(self, filename): # 实现一个简单的解析函数从文件名提取负载0,1,2,3 # 例如 97.mat 可能对应负载0 106.mat对应负载1需要查阅CWRU文档或自己总结映射关系 # 这里简化处理 if 0 in filename: return 0 # ... 其他逻辑 return 0 # 默认关键细节与避坑指南.mat文件版本问题CWRU数据集中的.mat文件是较老的MATLAB v5格式scipy.io.loadmat可以很好读取。但偶尔会遇到读取错误提示“Please use HDF reader”。这时可以尝试指定scipy.io.loadmat(file_path, simplify_cellsTrue)或者检查文件是否完整。信号长度不一致虽然大部分文件是120,000点但少数文件可能略有差异。在批量处理时务必统一长度可以采用截断或补零的方式。我通常统一截取前102,400个点方便后续做2的幂次方的FFT或者进行重采样。内存管理如果你要一次性加载所有数据几十个GB的原始信号内存可能会爆炸。建议采用“惰性加载”或“批量加载”策略即只在需要时才从硬盘读取文件并提取特征而不是一次性把所有信号读入内存。3.3 特征工程从振动信号到机器“看得懂”的语言原始振动信号对于机器学习模型来说太“原始”了。特征工程的目的就是将这些一维的时间序列转换为一组能够表征设备状态的关键指标。我的feature_extractor.py通常包含三大类特征1. 时域统计特征这是最直观、计算最快的一类特征。直接从信号的幅值统计信息中提取。def extract_time_features(signal): features {} features[mean] np.mean(signal) features[std] np.std(signal) # 标准差反映振动能量 features[rms] np.sqrt(np.mean(signal**2)) # 均方根值经典指标 features[peak] np.max(np.abs(signal)) # 峰值 features[skewness] scipy.stats.skew(signal) # 偏度衡量分布不对称性 features[kurtosis] scipy.stats.kurtosis(signal) # 峭度对冲击敏感故障诊断明星指标 features[crest_factor] features[peak] / features[rms] # 峰值因子 features[impulse_factor] features[peak] / np.mean(np.abs(signal)) # 脉冲因子 # ... 还可以计算波形因子、裕度因子等 return features为什么峭度Kurtosis这么重要健康轴承的振动信号近似服从高斯分布峭度值接近3。当出现局部损伤如点蚀、裂纹时会产生周期性冲击使信号分布出现“重尾”峭度值显著增大。因此峭度是早期故障非常敏感的指标。2. 频域特征通过快速傅里叶变换FFT将信号转换到频域观察能量在频率上的分布。故障特征频率Ball Pass Frequency Outer Race, BPFO; Ball Pass Frequency Inner Race, BPFI; Ball Spin Frequency, BSF是诊断的关键。def extract_freq_features(signal, fsSAMPLE_FREQ): n len(signal) # 加窗减少频谱泄漏 window np.hanning(n) signal_windowed signal * window # 计算FFT fft_vals np.fft.fft(signal_windowed) fft_freqs np.fft.fftfreq(n, 1/fs) # 取单边频谱 half_n n // 2 magnitude np.abs(fft_vals[:half_n]) * 2 / n # 求幅度谱 freq fft_freqs[:half_n] features {} # 1. 重心频率 features[fc] np.sum(freq * magnitude) / np.sum(magnitude) # 2. 均方频率 features[msf] np.sum((freq**2) * magnitude) / np.sum(magnitude) # 3. 频率方差 features[vf] np.sum(((freq - features[fc])**2) * magnitude) / np.sum(magnitude) # 4. 在故障特征频率附近提取幅值需要先根据轴承参数和转速计算BPFO, BPFI等 # bpfo calculate_bpfo(rpm, bearing_params) # idx np.argmin(np.abs(freq - bpfo)) # 找到最近频率索引 # features[bpfo_amp] magnitude[idx] return features计算故障特征频率是关键一步需要知道轴承的几何参数滚珠数、节径、接触角等。CWRU实验台架使用的轴承型号是SKF 6205-2RS JEM其参数是公开的。你需要编写一个函数根据转速RPM来计算这些频率。3. 时频域与非线-性特征这类特征能同时捕捉信号在时间和频率上的变化对非平稳信号故障冲击就是典型的非平稳瞬态特别有效。小波包能量熵使用小波包分解将信号分解到不同频带计算各频带的能量并进一步计算能量分布的不确定性熵。故障发生时能量会从某些频带转移到另一些频带熵值会变化。希尔伯特-黄变换HHT边际谱熵先进行经验模态分解EMD得到本征模函数IMF再对IMF做希尔伯特变换求瞬时频率和幅值最后计算边际谱的熵。这个方法自适应强但计算量较大。排列熵Permutation Entropy衡量时间序列的复杂度计算速度快对动态变化敏感。import pywt import antropy as ant def extract_time_freq_features(signal): features {} # 示例小波包分解3层db4小波并计算能量熵 wp pywt.WaveletPacket(datasignal, waveletdb4, modesymmetric, maxlevel3) # 获取第3层所有节点名称如aaa, aad, ... nodes [node.path for node in wp.get_level(3, natural)] energy_list [] for node in nodes: coeff wp[node].data energy np.sum(coeff**2) energy_list.append(energy) energy_total np.sum(energy_list) # 计算能量百分比和香农熵 energy_probs [e / energy_total for e in energy_list] features[wpt_energy_entropy] -np.sum([p * np.log2(p) for p in energy_probs if p 0]) # 计算排列熵 features[permutation_entropy] ant.perm_entropy(signal, order3, delay1, normalizeTrue) # 计算样本熵衡量复杂度 features[sample_entropy] ant.sample_entropy(signal, order2, metricchebyshev) return features3.4 构建数据集与模型训练示例将上述所有功能串联起来在main_demo.py中我们可以构建一个完整的机器学习流程# 1. 初始化加载器并获取所有文件信息 loader CWRULoader() loader.traverse_and_load() all_features [] all_labels [] # 2. 遍历每个文件提取特征 for i, file_path in enumerate(loader.file_paths): print(fProcessing {i1}/{len(loader.file_paths)}: {file_path}) signal loader.load_single_file(file_path) # 可选对信号进行预处理如去趋势、带通滤波 # signal scipy.signal.detrend(signal) # 提取特征 time_feat extract_time_features(signal) freq_feat extract_freq_features(signal, fs12000) tf_feat extract_time_freq_features(signal) # 合并所有特征字典 combined_feat {**time_feat, **freq_feat, **tf_feat} all_features.append(list(combined_feat.values())) all_labels.append(loader.labels[i]) # 3. 转换为数组 X np.array(all_features) y np.array(all_labels) # 4. 特征标准化非常重要 from sklearn.preprocessing import StandardScaler scaler StandardScaler() X_scaled scaler.fit_transform(X) # 5. 划分训练集和测试集建议按负载划分更符合实际 from sklearn.model_selection import train_test_split # 例如用负载0,1,2的数据训练负载3的数据测试 train_idx [i for i, load in enumerate(loader.load_conditions) if load in [0,1,2]] test_idx [i for i, load in enumerate(loader.load_conditions) if load 3] X_train, X_test X_scaled[train_idx], X_scaled[test_idx] y_train, y_test y[train_idx], y[test_idx] # 6. 训练一个简单的分类器如随机森林 from sklearn.ensemble import RandomForestClassifier from sklearn.metrics import classification_report, confusion_matrix clf RandomForestClassifier(n_estimators100, random_state42) clf.fit(X_train, y_train) y_pred clf.predict(X_test) # 7. 评估 print(classification_report(y_test, y_pred)) # 可以绘制混淆矩阵观察具体哪几类容易混淆通过这个流程你就能快速得到一个基于传统特征工程和机器学习模型的轴承故障诊断基线系统。在此基础上你可以尝试更复杂的特征或者转向深度学习模型如1D-CNN, LSTM直接端到端地从原始信号中学习特征。4. 高级应用与避坑经验实录掌握了基础流程后我们来看看如何进阶以及在实际操作中会遇到哪些“坑”。4.1 面向深度学习的信号预处理策略当你打算使用卷积神经网络CNN处理原始振动信号时预处理方式与特征工程模式有显著不同。数据标准化对于CNN通常对每个样本单独进行标准化如减均值除标准差而不是像传统机器学习那样在整个训练集上做全局标准化。这能让网络更关注信号的形状而非绝对幅值。数据增强振动信号的数据增强需要谨慎。常用的方法包括加性高斯白噪声添加微小的随机噪声提高模型鲁棒性。时间偏移对信号进行小幅度的循环平移。缩放对信号幅值进行轻微缩放。注意切勿使用在图像上常见的翻转、旋转等操作这会破坏振动信号的时间因果关系。输入格式1D-CNN的输入通常是(样本数, 信号长度, 1)的三维张量。如果使用2D-CNN如将时频谱图作为输入则需要先将信号转换为时频图像如短时傅里叶变换STFT图、小波尺度图。# 示例为1D-CNN准备数据 def prepare_data_for_1dcnn(file_paths, labels, segment_length1024, overlap0.5): 将长信号分割成固定长度的小段用于训练CNN all_segments [] all_seg_labels [] for file_path, label in zip(file_paths, labels): signal loader.load_single_file(file_path) # 分割信号 step int(segment_length * (1 - overlap)) for start in range(0, len(signal) - segment_length, step): segment signal[start:startsegment_length] # 样本级标准化 segment (segment - np.mean(segment)) / (np.std(segment) 1e-8) all_segments.append(segment) all_seg_labels.append(label) # 转换为 (n_samples, segment_length, 1) X np.array(all_segments).reshape(-1, segment_length, 1) y np.array(all_seg_labels) return X, y4.2 跨负载诊断真正的挑战与解决方案在CWRU数据集上轻松达到99%的准确率并不难难的是让你的模型在不同负载工况下都表现稳定。这是从实验室走向工业应用的关键一步。问题根源电机负载变化会导致轴承的受力状态改变进而影响振动信号的整体能量水平和频谱结构。一个在负载0下训练的分类器可能仅仅因为负载3的信号幅值整体变大就将其误判为故障。解决方案域自适应特征寻找对负载变化不敏感的特征。峭度、峰值因子等无量纲指标理论上对幅值变化有一定鲁棒性。小波包能量熵、排列熵等复杂度特征也可能更稳定。领域自适应Domain Adaptation这是一个前沿方向。使用对抗性训练等方法让模型学习到的特征表示中尽可能抹去“负载”这个域的信息只保留“健康状态”的信息。数据标准化策略尝试不同的标准化方法。除了全局标准化可以尝试对每个样本的频谱进行归一化如将频谱幅值总和归一化为1以消除能量差异。在数据划分上模拟真实场景这是最实用的一招。不要随机打乱所有数据再划分训练测试集这会导致模型“偷看”到未来或不同工况的数据分布造成虚假的高准确率。正确的做法是方案A严格选择某一种或几种负载的数据作为源域训练集剩下的完全不同负载的数据作为目标域测试集。这是最考验模型泛化能力的方式。方案B宽松将所有数据按负载分层然后在每个负载内部按比例划分训练/验证/测试。这样能保证每个负载的数据都出现在训练和测试集中评估的是模型对已知负载的识别能力。在我的实践中采用方案A用负载0、1的数据训练用负载2、3的数据测试使用精心挑选的时频域熵特征加上随机森林准确率可以从随机打乱时的99%以上下降到85%左右。这15%的差距就是算法需要真正攻克的技术难点。4.3 常见问题排查与性能优化技巧问题特征提取速度太慢尤其是小波变换和熵计算。排查使用cProfile或line_profiler工具定位耗时最长的函数。优化向量化操作避免在Python中使用for循环处理数组尽量使用NumPy的向量化函数。降低计算精度对于小波分解层数或排列熵的阶数(order)在满足需求的前提下适当降低。并行计算使用joblib或multiprocessing库对多个文件或样本进行并行特征提取。from joblib import Parallel, delayed def process_file(file_path): # 单个文件的处理逻辑 return features results Parallel(n_jobs4)(delayed(process_file)(fp) for fp in file_paths)问题模型过拟合在训练集上完美在测试集上很差。排查首先检查数据划分是否“泄漏”。确保没有同一个轴承、同一段信号的数据同时出现在训练集和测试集。优化增加正则化对于机器学习模型增加L2正则化参数对于深度学习模型使用Dropout、L2正则化、早停Early Stopping。简化模型减少神经网络层数或神经元数量减少随机森林的树深度或棵树。使用更丰富的特征有时过拟合是因为特征太少、太简单模型只能记住训练样本。增加更多样化的特征如多种熵特征、高阶谱特征可能反而会提升泛化能力。问题某些故障类别如不同尺寸的内圈故障总是分不清。排查绘制混淆矩阵精确查看哪些类被混淆。然后分别绘制这两类故障信号的时域波形、频谱图或包络谱进行对比。优化聚焦故障特征频率计算并突出在BPFI内圈故障频率附近的幅值或能量作为特征。不同故障尺寸可能主要影响冲击的强度能量而对频率位置影响较小需要寻找对冲击能量更敏感的特征如包络谱的幅值、小波系数的能量。尝试更强大的分类器从简单的SVM、随机森林升级到梯度提升树如XGBoost, LightGBM或更深的神经网络。数据层面检查这两类故障的样本数量是否严重不均衡考虑使用过采样如SMOTE或调整类别权重。5. 从CWRU出发下一步的探索方向当你熟练掌握了CWRU数据集的使用并搭建了一个不错的基线模型后你的旅程才刚刚开始。CWRU是一个完美的起点但它毕竟是一个在简单、稳定工况下采集的实验室数据。工业现场的环境要复杂恶劣得多。我的建议是以CWRU为基石逐步向更真实、更复杂的场景拓展挑战更复杂的数据集寻找包含变速、变载、复合故障、背景噪声更强的公开数据集例如美国辛辛那提大学的IMS数据集、法国Paderborn大学轴承数据集等。用你的模型去试试看看性能下降多少这就是你算法需要改进的空间。尝试迁移学习将在CWRU上预训练好的模型尤其是深度学习模型迁移到少量现场数据上进行微调。这是解决工业现场标注数据稀缺的有效途径。探索无监督/半监督方法现场大部分数据是没有标签的。研究如何利用大量无标签数据只有振动信号不知好坏进行异常检测或健康度评估比如使用自编码器、生成对抗网络GAN进行重构误差分析。关注“小样本”学习在工业场景中某些严重故障的样本可能极少。研究如何用极少的故障样本训练出有效的诊断模型这是一个极具实用价值的方向。最后把我整理好的数据包和Python程序分享给大家的初衷就是希望帮你省下最初那几天甚至几周摸索数据格式、编写基础代码的时间。这些工具是我在无数次调试和实验中打磨出来的包含了上述提到的诸多细节处理和避坑逻辑。你可以直接基于它开始你的研究把宝贵的时间投入到更核心的算法创新中去。记住工具是为你服务的理解数据背后的物理意义和实验逻辑才是做出有价值工作的根本。本文还有配套的精品资源点击获取