数据入口:压气机异常检测一维时间序列 - Heywhale.com
该数据为采样自工业压气机的一维时间序列数据。本文将通过无监督时间序列算法进行时间序列异常检测。针对时间序列数据,常用的无监督异常检测算法包括:孤立森林(Isolation Forest)、基于密度的局部离群因子检测(LOF)、自编码器(Autoencoders)等。根据数据特性可以选择合适的算法。时间序列数据可能需要预处理,如归一化、缺失值处理等,以确保算法的有效性。最后使用选定的算法对数据进行训练,并识别出异常点。
一:孤立森林
孤立森林(Isolation Forest)是一种高效的异常检测算法。它基于这样的观察:异常数据通常数量较少且与正常数据有较大差异,因此在数据集中更容易被孤立。孤立森林通过构建多棵随机的二叉树(孤立树),每棵树都随机选择特征和切分点来递归地分割数据,直到每个数据点都被孤立到自己的节点上。异常点由于其独特的属性,通常会在较少的分割步骤中就被孤立,因此它们在树中的路径较短。
孤立森林算法的主要特点包括:
- 高效性:具有线性时间复杂度,适合处理大规模数据集。
- 无需参数调整:算法性能不太依赖于参数设置,如树的数量和子采样的大小。
- 易于并行化:由于每棵树的构建是独立的,可以并行处理。
- 鲁棒性:对高维数据和稀疏数据表现良好。
算法的流程大致如下:
- 从数据集中随机抽取一定数量的样本作为子样本。
- 对于每个子样本,随机选择一个特征和一个切分点,构建一棵孤立树。
- 重复步骤1和2,构建多棵孤立树,形成孤立森林。
- 对于新的样本,通过计算其在森林中的平均路径长度来判断其是否为异常。
在Python中,可以使用sklearn.ensemble.IsolationForest
来实现孤立森林算法。通过调整参数如n_estimators
(树的数量)、max_samples
(构建子树的样本数)、contamination
(异常数据的比例估计)等,可以在不同数据集上优化算法的性能。
数据集包含三个特征:导叶开度、燃料流量(单位:𝑚3𝑁/ℎm3N/h)和压气机出口温度。这些特征都是数值型的,首先,我将进行数据探索,查看数据的统计描述和分布情况。
import pandas as pdfile_path = 'data.xlsx'
data = pd.read_excel(file_path)data_description = data.describe()
missing_values = data.isnull().sum()
data_description, missing_values
从数据的统计描述中,我们可以观察到以下几点:
- 导叶开度:范围在 0 到 85 之间,平均值约为 62。
- 燃料流量:范围在 0.0089 到 6.81 𝑚3𝑁/ℎm3N/h,平均值约为 3.39。
- 压气机出口温度:范围在 1 到 550 度,平均值约为 215.36 度。
所有特征都没有缺失值,这意味着我们不需要进行缺失值处理。
接下来,我将选择一个合适的无监督异常检测算法。计划使用孤立森林(Isolation Forest)算法进行异常检测。这是一种适用于高维数据的算法,特别适合于检测少量异常值。在应用孤立森林算法之前,我将对数据进行归一化处理,以确保算法的有效性。然后,我将训练孤立森林模型并识别出异常点。最后,我将检测结果进行可视化。
from sklearn.ensemble import IsolationForest
from sklearn.preprocessing import StandardScaler
import matplotlib.pyplot as plt
import seaborn as snsscaler = StandardScaler()
data_normalized = scaler.fit_transform(data)model = IsolationForest(n_estimators=100, max_samples='auto', contamination=float(0.01), random_state=42)model.fit(data_normalized)anomaly_scores = model.decision_function(data_normalized)
data['anomaly_score'] = anomaly_scoresdata['anomaly'] = model.predict(data_normalized)
anomalies = data[data['anomaly'] == -1]plt.figure(figsize=(10, 6))
sns.scatterplot(data=data, x='导叶开度', y='燃料流量m3N/h', hue='anomaly', palette='deep', s=100)
plt.scatter(anomalies['导叶开度'], anomalies['燃料流量m3N/h'], color='red', marker='x', s=100, label='Anomaly')
plt.title('Anomaly Detection using Isolation Forest')
plt.legend()
plt.show()num_anomalies = len(anomalies)
num_anomalies
在异常分数与预测中,decision_function
:计算每个样本的异常分数,分数越低,越可能是异常。然后预测每个样本是否为异常,返回1表示正常,-1表示异常。使用孤立森林算法,我们在数据集中检测到了 7 个异常点。这些异常点在可视化图中以红色 ‘x’ 标记出来。后续也可以调整算法参数来优化模型。
二:局部离群因子
局部离群因子(Local Outlier Factor, LOF)是一种基于密度的离群点检测算法。LOF算法的核心思想是,一个数据点如果是离群点,那么它与邻近点的密度相比会显得相对稀少。LOF算法通过计算每个数据点的局部离群因子来确定其是否为离群点。
LOF算法的工作原理可以概括为以下几个步骤:
k邻近距离(k-distance):对于数据集中的每个点,计算它到第k个最近邻点的距离,这个距离被称为k邻近距离。
k距离邻域:以每个点的k邻近距离为半径,画一个圆,圆内的点被认为是该点的k距离邻域内的点。
局部可达密度(Local Reachability Density, LRD):计算每个点的局部可达密度,即该点的k距离邻域内点的密度。
局部离群因子(LOF):对于每个点,计算其邻域内其他点的局部可达密度与该点的局部可达密度之比的平均数。如果这个比值显著大于1,那么该点可能是离群点。
在Python中,可以使用scikit-learn库中的LocalOutlierFactor
类来实现LOF算法。通过设置n_neighbors
参数来定义局部邻域的大小,contamination
参数来估计数据集中离群点的比例。
由于数据已经被标准化,接下来,我将使用基于密度的局部离群因子(LOF)方法来检测异常值。我将使用 sklearn
库中的 LocalOutlierFactor
类来计算每个数据点的 LOF 值,并标识出 LOF 值最高的数据点作为异常点:
from sklearn.neighbors import LocalOutlierFactorn_neighbors = 20lof = LocalOutlierFactor(n_neighbors=n_neighbors, metric='euclidean')
lof.fit_predict(data_normalized)lof_scores = lof.negative_outlier_factor_lof_anomalies = data[lof_scores < -1.5]lof_anomalies
可以看出也检测出来前7行数据为异常值。
三:自编码器
自编码器在时间序列无监督异常点检测中的应用主要体现在利用其强大的特征学习能力来识别数据中的异常模式。时间序列数据是按时间顺序排列的数据点集合,它们可以是连续的,也可以是离散的。在时间序列分析中,异常点或离群点是指那些显著偏离正常模式的数据点或数据段。
自编码器通过学习数据的有效表示来压缩和重建输入数据。在时间序列的上下文中,自编码器可以用来捕捉时间依赖性和模式,从而能够重建输入序列。如果某个数据点或序列无法被自编码器准确重建,这可能表明它是一个异常点。
在无监督异常检测的背景下,自编码器通常被训练为最小化重建误差,即输入数据和重建数据之间的差异。在训练过程中,自编码器学习到的正常时间序列数据的表示,可以用来识别那些与学习到的模式不匹配的异常数据点。
我将构建并训练一个自编码器模型来检测异常值。为此,我将设计一个简单的自编码器模型,并使用标准化后的数据来训练它。训练完成后,我将使用模型来重构数据,并计算每个数据点的重构误差。最后,我将标识出重构误差最大的数据点作为异常点。
from keras.layers import Input, Dense
from keras.models import Model
from keras.optimizers import Adaminput_dim = data_normalized.shape[1]
encoding_dim = 2 input_layer = Input(shape=(input_dim,))
encoded = Dense(encoding_dim, activation='relu')(input_layer)
decoded = Dense(input_dim, activation='sigmoid')(encoded)autoencoder = Model(input_layer, decoded)
encoder = Model(input_layer, encoded)autoencoder.compile(optimizer=Adam(learning_rate=0.001), loss='mse')autoencoder.fit(data_normalized, data_normalized, epochs=50, batch_size=32, shuffle=True, validation_split=0.2)data_reconstructed = autoencoder.predict(data_normalized)reconstruction_error = ((data_reconstructed - data_normalized) ** 2).mean(axis=1)autoencoder_anomalies = data[reconstruction_error > 0.5]autoencoder_anomalies
可以看出也检测出前几行数据为时间序列异常值。
想要探索多元化的数据分析视角,可以关注之前发布的相关内容。