sktime卷积神经网络:CNN时间序列分类实战
1. 时间序列分类的痛点与挑战
时间序列数据在金融、气象、工业监测等领域无处不在,但传统机器学习方法难以捕捉其隐含的 temporal patterns(时间模式)。你是否还在为以下问题困扰:
- 如何从电力负荷曲线中识别用户类型?
- 如何基于传感器数据判断设备运行状态?
- 传统特征工程耗时且效果有限?
本文将通过sktime的CNNClassifier实现端到端时间序列分类,全程代码可复现,读完你将掌握:
- 卷积神经网络在时间序列中的工作原理
- sktime-CNN模型的参数调优技巧
- 完整工业级分类项目的实现流程
2. CNN时间序列分类原理
2.1 一维卷积的时间特征提取
传统CNN处理图像的2D卷积核在时间序列中演变为1D卷积核,通过滑动窗口捕捉局部时间模式:
关键创新点:
- 卷积核长度(kernel_size)决定时间依赖捕捉范围
- 多通道滤波器(filter_sizes)提取不同尺度特征
- 池化层降低计算复杂度并增强平移不变性
2.2 sktime-CNN网络架构
sktime的CNNNetwork实现了Zhao et al. (2017)提出的经典架构:
# 核心网络结构伪代码
input = Input(shape=(n_timesteps, n_channels))
x = Conv1D(filters=6, kernel_size=7, padding='same', activation='sigmoid')(input)
x = AveragePooling1D(pool_size=3)(x)
x = Conv1D(filters=12, kernel_size=7, padding='same', activation='sigmoid')(x)
x = AveragePooling1D(pool_size=3)(x)
output = Flatten()(x)
3. 环境准备与数据加载
3.1 安装依赖
pip install sktime tensorflow numpy pandas scikit-learn matplotlib
3.2 数据集介绍
使用意大利电力需求数据集:
- 1096个日用电负荷曲线实例
- 每实例24个时间点(小时)
- 2个类别(高/低需求日)
from sktime.datasets import load_italy_power_demand
# 加载数据(numpy3D格式:[实例数, 变量数, 时间步])
X_train, y_train = load_italy_power_demand(split="train", return_type="numpy3D")
X_test, y_test = load_italy_power_demand(split="test", return_type="numpy3D")
print(f"训练集形状: {X_train.shape}") # (67, 1, 24)
print(f"类别分布: {pd.Series(y_train).value_counts()}")
4. CNN模型实战开发
4.1 基础模型构建
from sktime.classification.deep_learning import CNNClassifier
# 初始化模型
cnn = CNNClassifier(
n_epochs=200, # 训练轮次
batch_size=16, # 批次大小
kernel_size=7, # 卷积核长度
avg_pool_size=3, # 池化窗口大小
n_conv_layers=2, # 卷积层数量
filter_sizes=[6, 12], # 各卷积层滤波器数量
verbose=True,
random_state=42
)
# 训练模型
cnn.fit(X_train, y_train)
4.2 模型结构可视化
# 打印模型摘要
cnn.model_.summary()
# 输出示例(部分):
# Model: "model"
# _________________________________________________________________
# Layer (type) Output Shape Param #
# =================================================================
# input_1 (InputLayer) [(None, 24, 1)] 0
# _________________________________________________________________
# conv1d (Conv1D) (None, 24, 6) 48
# _________________________________________________________________
# average_pooling1d (AveragePo (None, 8, 6) 0
# _________________________________________________________________
# conv1d_1 (Conv1D) (None, 8, 12) 516
# _________________________________________________________________
# average_pooling1d_1 (Average (None, 2, 12) 0
# _________________________________________________________________
# flatten (Flatten) (None, 24) 0
# _________________________________________________________________
# dense (Dense) (None, 2) 50
# =================================================================
4.3 模型评估与预测
# 预测概率
y_proba = cnn.predict_proba(X_test)
# 预测类别
y_pred = cnn.predict(X_test)
# 评估指标
from sklearn.metrics import accuracy_score, classification_report
print(f"测试集准确率: {accuracy_score(y_test, y_pred):.4f}")
print(classification_report(y_test, y_pred))
5. 超参数调优实践
5.1 参数影响分析
| 参数 | 取值范围 | 对模型影响 |
|---|---|---|
| kernel_size | 3-15 | 较小值捕捉局部模式,较大值捕捉全局趋势 |
| filter_sizes | [4-64] | 数量越多特征表达能力越强,易过拟合 |
| n_conv_layers | 1-4 | 层数增加可提取更抽象特征 |
| batch_size | 8-64 | 较小值收敛快但波动大 |
5.2 网格搜索调优
from sklearn.model_selection import GridSearchCV
import numpy as np
# 参数网格
param_grid = {
"kernel_size": [5, 7, 9],
"filter_sizes": [[4,8], [6,12], [8,16]],
"n_conv_layers": [2, 3]
}
# 网格搜索
grid_search = GridSearchCV(
estimator=CNNClassifier(n_epochs=100, verbose=False),
param_grid=param_grid,
cv=3,
scoring="accuracy",
n_jobs=-1
)
grid_search.fit(X_train, y_train)
print(f"最佳参数: {grid_search.best_params_}")
print(f"最佳交叉验证准确率: {grid_search.best_score_:.4f}")
5.3 最佳模型训练
# 使用最佳参数初始化模型
best_cnn = grid_search.best_estimator_
best_cnn.n_epochs = 300 # 增加训练轮次
best_cnn.verbose = True
# 重新训练最佳模型
best_cnn.fit(X_train, y_train)
6. 训练过程可视化
import matplotlib.pyplot as plt
# 提取训练历史
history = best_cnn.history.history
# 绘制损失曲线
plt.figure(figsize=(12, 4))
plt.subplot(1, 2, 1)
plt.plot(history["loss"], label="训练损失")
plt.plot(history["val_loss"], label="验证损失")
plt.title("模型损失曲线")
plt.xlabel("Epoch")
plt.ylabel("Loss")
plt.legend()
# 绘制准确率曲线
plt.subplot(1, 2, 2)
plt.plot(history["accuracy"], label="训练准确率")
plt.plot(history["val_accuracy"], label="验证准确率")
plt.title("模型准确率曲线")
plt.xlabel("Epoch")
plt.ylabel("Accuracy")
plt.legend()
plt.tight_layout()
plt.show()
7. 与传统方法对比实验
from sktime.classification.distance_based import KNeighborsTimeSeriesClassifier
from sktime.classification.interval_based import TimeSeriesForestClassifier
from sklearn.metrics import accuracy_score
# 定义对比模型
models = {
"CNN": best_cnn,
"KNN-DTW": KNeighborsTimeSeriesClassifier(distance="dtw"),
"TimeSeriesForest": TimeSeriesForestClassifier(n_estimators=100)
}
# 评估各模型
results = {}
for name, model in models.items():
if name != "CNN": # CNN已训练
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
results[name] = accuracy_score(y_test, y_pred)
# 打印结果
print("各模型准确率对比:")
for name, acc in results.items():
print(f"{name}: {acc:.4f}")
典型结果:
各模型准确率对比:
CNN: 0.9412
KNN-DTW: 0.8824
TimeSeriesForest: 0.8529
8. 工业级应用最佳实践
8.1 数据预处理管道
from sktime.transformations.series.adapt import TabularToSeriesAdaptor
from sktime.transformations.compose import ColumnTransformer
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
# 创建预处理管道
preprocessor = ColumnTransformer(
transformers=[
("scale", TabularToSeriesAdaptor(StandardScaler()), [0])
]
)
# 构建完整管道
pipeline = Pipeline([
("preprocessing", preprocessor),
("classifier", best_cnn)
])
# 训练管道
pipeline.fit(X_train, y_train)
8.2 模型保存与加载
import joblib
# 保存模型
joblib.dump(best_cnn, "cnn_time_series_classifier.pkl")
# 加载模型
loaded_cnn = joblib.load("cnn_time_series_classifier.pkl")
y_pred = loaded_cnn.predict(X_test)
9. 总结与展望
本文系统介绍了sktime中CNNClassifier的原理与实战,通过完整案例展示了从数据加载到模型部署的全流程。关键收获:
- 卷积神经网络通过局部特征提取有效捕捉时间序列模式
- 参数调优中,kernel_size和filter_sizes对性能影响显著
- 在电力负荷分类任务中,CNN准确率优于传统KNN和时间序列森林
未来可探索方向:
- 结合注意力机制增强长序列建模能力
- 尝试更深层次的网络结构或预训练模型迁移
- 多变量时间序列分类的扩展应用
点赞+收藏本文,关注获取更多sktime高级教程!下期预告:基于LSTM-FCN的多变量时间序列异常检测。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



