【AI】代码实战- 基于时间序列的轴承检测1

长期更新好文,关注收藏++

定义

  • 背景:在轴承故障诊断(Bearing Fault Diagnosis / Detection)的机器学习或深度学习任务中,训练和测试集是 id + N列序号 的数据结构,是典型的时间序列(Time Series)或信号截取(Signal Segment)的数据表达方式。每一行代表一段轴承的振动信号样本,id 用来区分不同的样本,而后面的 N列 则是这段样本中连续采样的振动数值。

数据集

你手上的数据是DataCastle(DC竞赛)举办的"轴承故障检测训练赛"的官方数据集。 1

这个数据集是主办方基于经典轴承数据集(如 CWRU 凯斯西储大学数据集)进行截取和加工后,专门用来做算法竞赛的。

该赛题将以下状态交叉组合,形成了 0 到 9 共 10 个分类标签(Label):

  • 0:正常工作状态

  • 1, 2, 3:内圈故障(分别对应 3 种不同直径的损伤)

  • 4, 5, 6:外圈故障(分别对应 3 种不同直径的损伤)

  • 7, 8, 9:滚珠故障(分别对应 3 种不同直径的损伤) 1

  • 列数结构: 每行共有 6002 列(包含第 1 列 id,中间的 6000 列时序振动数据,以及最后一列 label 标签)。

  • 样本数量: 训练集(train.csv)通常有 792 条数据,测试集(test_data.csv)有 528 条数据。

  • 物理意义: 中间的 6000 列是在固定采样率下连续截取的 6000 个高频振动加速度值,严格按时间先后顺序排列。 1, 2, 3, 4

解题策略

针对这个经典的 DC 轴承 10 分类赛题,目前行业内有两套最标准、效果最好的解题基线(Baseline):

方案 A:一维卷积神经网络 (1D-CNN) ------ 最推荐、准确率最高

不需要做任何手动的特征工程,直接让神经网络去学习波形图里的周期性冲击特征。

  1. 数据读取与变形:
    读入 train.csv 后,切出中间的 6000 列。使用 NumPy 将其形状由二维的 (792, 6000) 转换为三维的 (792, 6000, 1),以符合卷积网络的输入规范。
  2. 网络设计要点:
  • 大卷积核开路: 第一层一维卷积(Conv1D)的卷积核一定要设得比较大(如 kernel_size=64 或 128),用来捕捉轴承旋转一周的长周期特征。
    • 小卷积核堆叠: 后续的卷积层可以使用较小的卷积核(如 kernel_size=3 或 5),配合池化层(MaxPooling1D)逐步压缩时序长度并提取深层特征。
    • 输出层: 全连接层最后输出 Dense(10, activation='softmax') 进行 10 分类预测。

方案 B:时域统计特征 + LightGBM / XGBoost ------ 运行最快

如果你更熟悉传统机器学习,可以直接提取这 6000 个点的波形统计特征:

  1. 特征提取: 对每一行的 6000 个数字,计算它的均值、标准差、峭度(Kurtosis,对冲击极其敏感)、偏度、峰值因素、脉冲因素等,把 6000 列压缩成 20~30 列核心特征指标。
  2. 模型训练: 将提取出的特征矩阵送入 LightGBM 或 XGBoost 进行多分类训练。这种方法可以在几秒钟内完成训练,且准确率也非常可观。

实战

  • 本期是第一期,基础机器学习。第二期为方案B。第三期为方案A。

1. 读取数据

py 复制代码
# %%
import pandas as pd
import numpy as np
from scipy import stats
import warnings
warnings.filterwarnings('ignore')

# %% [markdown]
# # 1.数据读取

# %%
train_data = pd.read_csv("D:\\GIT\\ml_dl\\ml\\classify\\bearing\\train.csv")

# %%
test_data = pd.read_csv("D:\\GIT\\ml_dl\\ml\\classify\\bearing\\test_data.csv")

| | id | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | ... | 5992 | 5993 | 5994 | 5995 | 5996 | 5997 | 5998 | 5999 | 6000 | label |
| 0 | 1 | 0.563650 | 1.069229 | -0.837759 | -1.122021 | 0.433296 | 0.770755 | -0.477153 | -0.588421 | 0.455224 | ... | -0.050761 | 0.220506 | 0.036548 | -0.097461 | -0.084060 | -0.007716 | -0.049949 | -0.018274 | 0.021523 | 7 |
| 1 | 2 | 0.061333 | 0.058830 | 0.056952 | 0.068634 | 0.073433 | 0.072390 | 0.042975 | -0.007302 | -0.026286 | ... | 0.061333 | 0.107437 | 0.104516 | 0.063419 | -0.014394 | -0.048607 | -0.009388 | 0.058830 | 0.129342 | 0 |
| 2 | 3 | 0.035736 | 0.010964 | -0.164872 | -0.167714 | -0.125075 | -0.104771 | -0.016650 | 0.151471 | 0.137258 | ... | 4.272044 | -1.991455 | -2.922208 | 1.937039 | 0.704156 | -2.085667 | 0.203044 | 0.739892 | -2.149829 | 9 |
| 3 | 4 | -0.046700 | 0.060913 | 0.009340 | -0.093400 | -0.067817 | 0.022335 | 0.006091 | -0.076751 | -0.032893 | ... | 0.095025 | -0.000406 | 0.091776 | 0.074314 | -0.082842 | -0.110050 | -0.028020 | 0.025990 | -0.050355 | 9 |

4 5 0.162922 -0.377662 0.014457 0.565437 -0.203369 -0.511508 0.410961 0.228546 -0.515244 ... -0.093563 -0.263632 0.114517 0.209541 -0.184851 -0.075370 0.286211 0.005685 -0.223348 7

5 rows × 6002 columns

2. 观察数据

py 复制代码
# %%
train_data.head(5)

# %% [markdown]
# # 2.目标值分布观察
# 数据量较少。但是分布还算均匀。

# %%
y_label_count = train_data.groupby(['label'])['label'].count()
y_label_count

# %% [markdown]
# 注意:同一列的数据不一定是同一个时间点的采样数据,即不要把每一列当作一个特征
# 先看眼数据,啥也看不出来。数据比较完整,没有缺失,不用也不能进行填充等操作

# %%
X_train = train_data.iloc[:,1:6001]
X_train.head()

label

0 177

1 46

2 43

3 50

4 51

5 47

6 52

7 140

8 45

9 141

Name: label, dtype: int64

| | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | ... | 5991 | 5992 | 5993 | 5994 | 5995 | 5996 | 5997 | 5998 | 5999 | 6000 |
| 0 | 0.563650 | 1.069229 | -0.837759 | -1.122021 | 0.433296 | 0.770755 | -0.477153 | -0.588421 | 0.455224 | 0.555122 | ... | -0.150659 | -0.050761 | 0.220506 | 0.036548 | -0.097461 | -0.084060 | -0.007716 | -0.049949 | -0.018274 | 0.021523 |
| 1 | 0.061333 | 0.058830 | 0.056952 | 0.068634 | 0.073433 | 0.072390 | 0.042975 | -0.007302 | -0.026286 | -0.006050 | ... | 0.033796 | 0.061333 | 0.107437 | 0.104516 | 0.063419 | -0.014394 | -0.048607 | -0.009388 | 0.058830 | 0.129342 |
| 2 | 0.035736 | 0.010964 | -0.164872 | -0.167714 | -0.125075 | -0.104771 | -0.016650 | 0.151471 | 0.137258 | 0.045076 | ... | 1.151665 | 4.272044 | -1.991455 | -2.922208 | 1.937039 | 0.704156 | -2.085667 | 0.203044 | 0.739892 | -2.149829 |
| 3 | -0.046700 | 0.060913 | 0.009340 | -0.093400 | -0.067817 | 0.022335 | 0.006091 | -0.076751 | -0.032893 | 0.023553 | ... | 0.137258 | 0.095025 | -0.000406 | 0.091776 | 0.074314 | -0.082842 | -0.110050 | -0.028020 | 0.025990 | -0.050355 |

4 0.162922 -0.377662 0.014457 0.565437 -0.203369 -0.511508 0.410961 0.228546 -0.515244 0.013157 ... 0.216039 -0.093563 -0.263632 0.114517 0.209541 -0.184851 -0.075370 0.286211 0.005685 -0.223348

5 rows × 6000 columns

3. 特征提取

py 复制代码
# %% [markdown]
# # 3.特征提取 提取和,均值,方差等

# %%
X_train_trans = pd.DataFrame()
X_train_trans['sum'] = np.sum(X_train,axis =1)
X_train_trans['abs_sum'] = np.sum(np.abs(X_train),axis =1)
X_train_trans['per5'] = np.percentile(X_train,q=5,axis =1) 
X_train_trans['per95'] = np.percentile(X_train,q=95,axis =1) 
X_train_trans['per99'] = np.percentile(X_train,q=99,axis =1) 

X_train_trans['mean'] = np.mean(X_train,axis =1)
X_train_trans['min'] = np.min(X_train,axis =1)
X_train_trans['max'] = np.max(X_train,axis =1)
X_train_trans['std'] = np.std(X_train,axis =1)
X_train_trans['var'] = np.var(X_train,axis =1)
X_train_trans['median'] = np.median(X_train,axis =1)
X_train_trans['skew'] = stats.skew(X_train,axis =1)
X_train_trans['kurtosis'] = stats.kurtosis(X_train,axis =1)  
X_train_trans['label'] =train_data['label']

y = pd.DataFrame()
y['label'] =train_data['label']
X_train_trans.head()

# %% [markdown]
# 从转换后的特征来看,不同label的数据还是比较有区分度的。

# %%
test_trans = pd.DataFrame()
test_trans['id'] = test_data['id']
test_trans['sum'] = np.sum(test_data.iloc[:,1:6001],axis =1)
test_trans['abs_sum'] = np.sum(np.abs(test_data.iloc[:,1:6001]),axis =1)
test_trans['per5'] = np.percentile(test_data.iloc[:,1:6001],q=5,axis =1) 
test_trans['per95'] = np.percentile(test_data.iloc[:,1:6001],q=95,axis =1) 
test_trans['per99'] = np.percentile(test_data.iloc[:,1:6001],q=99,axis =1) 
test_trans['mean'] = np.mean(test_data.iloc[:,1:6001],axis =1)
test_trans['min'] = np.min(test_data.iloc[:,1:6001],axis =1)
test_trans['max'] = np.max(test_data.iloc[:,1:6001],axis =1)
test_trans['std'] = np.std(test_data.iloc[:,1:6001],axis =1)
test_trans['var'] = np.var(test_data.iloc[:,1:6001],axis =1)
test_trans['median'] = np.median(test_data.iloc[:,1:6001],axis =1)
test_trans['skew'] = stats.skew(test_data.iloc[:,1:6001],axis =1)
test_trans['kurtosis'] = stats.kurtosis(test_data.iloc[:,1:6001],axis =1) 
test_trans.head()

| | sum | abs_sum | per5 | per95 | per99 | mean | min | max | std | var | median | skew | kurtosis | label |
| 0 | 28.589395 | 2154.024642 | -1.004296 | 0.971362 | 1.892394 | 0.004765 | -3.003019 | 3.236114 | 0.583343 | 0.340289 | 0.007919 | 0.000519 | 4.984610 | 7 |
| 1 | 91.983113 | 325.233054 | -0.098466 | 0.119537 | 0.160219 | 0.015331 | -0.222801 | 0.221132 | 0.065739 | 0.004322 | 0.017524 | -0.205528 | 0.036342 | 0 |
| 2 | 19.617697 | 1605.012177 | -0.637192 | 0.628238 | 1.901311 | 0.003270 | -5.501272 | 5.912233 | 0.540327 | 0.291954 | 0.002843 | 0.231480 | 21.957896 | 9 |
| 3 | 24.154104 | 955.968911 | -0.277378 | 0.313520 | 1.300825 | 0.004026 | -3.955295 | 3.712455 | 0.366301 | 0.134176 | 0.003249 | -0.492159 | 34.973034 | 9 |

4 79.547894 976.343474 -0.332667 0.357910 0.703714 0.013258 -1.754299 1.550606 0.233977 0.054745 0.010802 -0.048808 5.036917 7

| | id | sum | abs_sum | per5 | per95 | per99 | mean | min | max | std | var | median | skew | kurtosis |
| 0 | 1 | 20.936670 | 1593.757047 | -0.583690 | 0.584421 | 2.087291 | 0.003489 | -4.631026 | 5.202391 | 0.537096 | 0.288472 | 0.003249 | -0.019100 | 17.459809 |
| 1 | 2 | 36.363946 | 3711.522106 | -1.285755 | 1.312496 | 2.201414 | 0.006061 | -2.891751 | 3.168703 | 0.809820 | 0.655808 | -0.003452 | 0.085543 | 1.154068 |
| 2 | 3 | 39.485544 | 984.972515 | -0.299287 | 0.312749 | 1.293028 | 0.006581 | -3.624334 | 3.813977 | 0.361151 | 0.130430 | 0.006497 | -0.474609 | 30.183324 |
| 3 | 4 | 57.501702 | 311.344067 | -0.097423 | 0.109940 | 0.148328 | 0.009584 | -0.243246 | 0.197559 | 0.063453 | 0.004026 | 0.011891 | -0.156539 | -0.127848 |

4 5 26.891785 733.222105 -0.241866 0.261204 0.358509 0.004482 -0.518818 0.556503 0.152550 0.023271 0.003411 0.046709 -0.115646

4. 分类分布查看

py 复制代码
# %% [markdown]
# 画一个分类散点图,看看分布情况。pca降到2维画平面图

# %%
from sklearn.decomposition import PCA
var=["sum","abs_sum","per5","per95","per99","mean","min","max","std","var","median","skew","kurtosis"]
pca = PCA(n_components=2)
pca.fit(X_train_trans[var])
X_pca=pca.transform(X_train_trans[var])
print(pca.explained_variance_ratio_)  
X_pca_df =pd.DataFrame(X_pca) 
pic_x=pd.concat([X_pca_df,y],axis=1) 

# %%
import matplotlib.pyplot as plt
colors=['blue','orange','green','red','purple','brown','pink','gray','olive','cyan'] 
for i in range(0,10):
    Xi=pic_x[pic_x['label']==i][0]
    yi=pic_x[pic_x['label']==i][1]
    plt.scatter(Xi, yi, s=20, c=colors[i], label=i)

# %%
state_list=[0,1]
for i in state_list:
    Xi=pic_x[pic_x['label']==i][0]
    yi=pic_x[pic_x['label']==i][1]
    plt.scatter(Xi, yi, s=20, c=colors[i], label=i)

# %%
state_list=[1,2]
for i in state_list:
    Xi=pic_x[pic_x['label']==i][0]
    yi=pic_x[pic_x['label']==i][1]
    plt.scatter(Xi, yi, s=20, c=colors[i], label=i)

# %% [markdown]
# 从上面的图可以看出来,正常状态和异常状态区分度很好。但1-9异常状态间区分度不太好。说明选取的特征还不够,有时间继续探索补充特征吧。

5.分类算法,直接用随机森林、GBDT

py 复制代码
# %%
# 验证集效果
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix, accuracy_score
clf = RandomForestClassifier(n_estimators=50)
var=["sum","abs_sum","per5","per95","per99","mean","min","max","std","var","median","skew","kurtosis"]
x_train, x_val, y_train, y_val = train_test_split(X_train_trans[var], y , test_size=0.2)
clf.fit(x_train, y_train)
print(confusion_matrix(y_val, clf.predict(x_val)))
print(accuracy_score(y_val, clf.predict(x_val)))

# %%
from sklearn.ensemble import GradientBoostingClassifier 
gb_clf = GradientBoostingClassifier(n_estimators=50) 
gb_clf.fit(x_train, y_train)
print(confusion_matrix(y_val, gb_clf.predict(x_val)))
print(accuracy_score(y_val, gb_clf.predict(x_val)))

# %% [markdown]
# 分别用随机森林和梯度boosting,效果都不错,但是因为样本量很少,准确率在95%-99%之间吧。上传得到全部数据集上结果97%

# %%
# 看看训练集全部训练后测试集的效果
clf.fit(X_train_trans[var], y )
y_test=clf.predict(test_trans[var]) 
test_trans['label']=y_test
test_trans.to_csv("D:\\GIT\\ml_dl\\ml\\classify\\bearing\\sample.csv",index=0,header=1,columns=['id','label'])

# %%
相关推荐
OFIRM碳基硅基1 小时前
西游金蝉劫 IP · 之 《金蝉子前传渡缘劫》电影 20 亿票房触发 · 项目专项扶持协议 总览 拉格朗日光影动画-西游金蝉劫项目组
大数据·人工智能·西游金蝉劫·蝎子精·蝎子精女妖王·金蝉子前传渡缘劫
RSABLOCKCHAIN1 小时前
读懂AI-Agent项目Career-ops项目的底层原理
ai
银空飞羽1 小时前
职型求职工具实测:把简历分析、岗位匹配和定向优化串成一条求职链路
人工智能·经验分享·面试·职场和发展·跳槽·求职招聘·创业创新
ChaITSimpleLove1 小时前
AI时代 “本体” 的 “标准化” 定义
人工智能·dsl·rdf·ontology·ai本体·json-ld
FL16238631292 小时前
基于YOLOv8的智慧校园人脸识别和公路汽车检测项目源码+训练好的模型
人工智能
进化矩阵2 小时前
别把指标当目的:当数字开始反噬你
大数据·人工智能·职场和发展·创业创新
万物智能信息科技2 小时前
电容触摸 FT5406,另一颗芯片、同一条总线—【万物智能之开源鸿蒙OpenHarmony系统实战开发系列教程】
人工智能·华为·开源·harmonyos·鸿蒙
doudoudalao2 小时前
TikTok 带货视频怎么做?AI 一键生成带货视频提示词分享,怎么写出爆款的 AI 带货视频提示词
人工智能
十正2 小时前
把表变成模型够得着的句柄
人工智能·ai·agent