You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无异常训练集的信号数据无监督异常检测模型选型及参数咨询

解决训练集无异常样本时的PyOD算法参数问题

嘿,这个问题我之前碰到过不少新手朋友问,确实PyOD里的KNN、Isolation Forest这类算法默认假设训练集里存在异常样本,所以contamination参数要求必须大于0,刚好和你训练集全正常的情况冲突。不过没关系,针对你这种仅用正常样本训练的异常检测场景,我们有专门的思路和方案,一步步来:

第一步:先处理3D信号数据的维度问题

你的数据是(1700, 64, 100)——1700个样本,每个样本是64通道×100时间步的信号,但PyOD的大部分算法只接受2D输入(样本数×特征数)。所以首先要把3D数据转成2D,推荐两种方法:

  • 统计特征提取:对每个通道的100个时间步提取时域/统计特征,比如均值、方差、最大值、最小值、标准差、偏度、峰度。这样每个样本会变成64×7=448维的特征向量,最终得到(1700, 448)的2D数据。
  • 降维/特征压缩:用自编码器(AutoEncoder)、PCA等方法把每个(64,100)的样本压缩成固定长度的特征向量,适合不想手动设计特征的场景。

第二步:选择适配无异常训练集的模型

方法1:用One-Class SVM(专门针对仅正常样本的场景)

Sklearn里的OneClassSVM不需要指定异常比例,专门为只有正常样本的一类分类设计,完全适配你的情况:

from sklearn.svm import OneClassSVM
from sklearn.preprocessing import StandardScaler
import numpy as np

# 假设X_train_2d是你转好的2D训练数据
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train_2d)

# nu参数:控制支持向量的比例,可近似设置为你预期的异常比例(比如0.01)
oc_svm = OneClassSVM(nu=0.01, kernel='rbf')
oc_svm.fit(X_train_scaled)

# 验证集预测:1表示正常,-1表示异常
X_val_scaled = scaler.transform(X_val_2d)
y_pred = oc_svm.predict(X_val_scaled)
# 可以把-1转成1(异常),1转成0(正常)方便后续评估
y_pred = np.where(y_pred == -1, 1, 0)

方法2:用自编码器(AutoEncoder)基于重构误差检测异常

自编码器通过学习正常样本的重构模式,异常样本的重构误差会远高于正常样本,完全不需要训练集里有异常:

from tensorflow.keras.models import Model
from tensorflow.keras.layers import Input, Dense
import numpy as np

# 构建自编码器
input_dim = X_train_2d.shape[1]
encoding_dim = 32  # 可根据需求调整

input_layer = Input(shape=(input_dim,))
encoder = Dense(encoding_dim, activation='relu')(input_layer)
decoder = Dense(input_dim, activation='sigmoid')(encoder)

autoencoder = Model(inputs=input_layer, outputs=decoder)
autoencoder.compile(optimizer='adam', loss='mse')

# 仅用正常样本训练
autoencoder.fit(X_train_scaled, X_train_scaled, epochs=50, batch_size=32, validation_split=0.1)

# 计算验证集重构误差
X_val_recon = autoencoder.predict(X_val_scaled)
recon_error = np.mean(np.square(X_val_scaled - X_val_recon), axis=1)

# 用验证集的正常样本确定阈值(比如取正常样本误差的99分位数)
normal_recon_error = recon_error[y_val == 0]  # y_val是验证集真实标签,0=正常,1=异常
threshold = np.percentile(normal_recon_error, 99)

# 预测:误差超过阈值即为异常
y_pred = (recon_error > threshold).astype(int)

方法3:绕开PyOD的contamination参数限制

如果你还是想用PyOD里的KNN/Isolation Forest,其实可以先设置一个极小的contamination值(比如0.001),训练后不用默认阈值,而是在验证集上手动确定最优阈值:

from pyod.models.iforest import IForest
from sklearn.metrics import precision_recall_curve
import numpy as np

# 设置极小的contamination,训练过程其实不依赖这个参数,只是避免报错
iforest = IForest(contamination=0.001, random_state=42)
iforest.fit(X_train_2d)

# 获取验证集的异常得分
val_scores = iforest.decision_function(X_val_2d)

# 根据验证集真实标签找最优阈值(比如用F1分数最高的阈值)
precision, recall, thresholds = precision_recall_curve(y_val, val_scores)
f1_scores = 2 * (precision * recall) / (precision + recall)
best_threshold = thresholds[np.argmax(f1_scores)]

# 用最优阈值预测
y_pred = (val_scores > best_threshold).astype(int)

额外新手建议

  • 信号数据可以试试频域特征(比如FFT提取频谱、小波变换),有时比时域特征的异常检测效果更好;
  • 先从One-Class SVM+手动提取统计特征开始上手,流程简单,容易理解;
  • 可以把多个模型的得分融合(比如SVM的异常得分+自编码器的重构误差),进一步提升检测性能。

内容的提问来源于stack exchange,提问作者Jinter

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:21:34