在机器学习领域,异常检测是一种重要的任务,它可以帮助识别出不符合预期模式的数据点。支持向量机(SVM)是一种常用的分类算法,它也可以被用来进行异常检测。在某些情况下,可能需要处理非线性可分的数据,这时候可以使用核技巧来扩展SVM的能力。
在这篇文章中,将探讨如何使用基于径向基函数(RBF)核的OneClassSVM和基于随机梯度下降(SGD)的SGDOneClassSVM来进行异常检测。首先,使用核近似方法来应用SGDOneClassSVM,这是一种在线性SVM上使用SGD的版本。值得注意的是,SGDOneClassSVM的计算复杂度与样本数量线性相关,而核化的OneClassSVM的复杂度至多为样本数量的二次方。本例的目的不是为了展示这种近似在计算时间上的好处,而是为了展示在一个小规模数据集上可以得到相似的结果。
首先需要生成一些训练数据和测试数据,包括一些正常的新观测值和一些异常的新观测值。然后,使用OneClassSVM的超参数来拟合模型,并预测训练数据、测试数据和异常数据的标签。通过比较预测结果,可以评估模型在训练集和新观测值上的表现。
在下面的代码示例中,首先设置了一些基本的参数,包括随机状态和字体大小。然后,生成了训练数据和测试数据,并使用OneClassSVM和SGDOneClassSVM分别进行训练和预测。还使用了决策边界显示工具来可视化模型的决策边界。最后,展示了模型在训练集和新观测值上的错误率。
import matplotlib.pyplot as plt
import numpy as np
from sklearn.kernel_approximation import Nystroem
from sklearn.linear_model import SGDOneClassSVM
from sklearn.pipeline import make_pipeline
from sklearn.svm import OneClassSVM
# 设置字体大小
font = {"weight": "normal", "size": 15}
matplotlib.rc("font", **font)
# 设置随机状态
random_state = 42
rng = np.random.RandomState(random_state)
# 生成训练数据
X = 0.3 * rng.randn(500, 2)
X_train = np.r_[X + 2, X - 2]
# 生成一些正常的新观测值
X = 0.3 * rng.randn(20, 2)
X_test = np.r_[X + 2, X - 2]
# 生成一些异常的新观测值
X_outliers = rng.uniform(low=-4, high=4, size=(20, 2))
# OneClass SVM超参数
nu = 0.05
gamma = 2.0
# 拟合One-Class SVM
clf = OneClassSVM(gamma=gamma, kernel="rbf", nu=nu)
clf.fit(X_train)
y_pred_train = clf.predict(X_train)
y_pred_test = clf.predict(X_test)
y_pred_outliers = clf.predict(X_outliers)
# 使用核近似和SGD拟合One-Class SVM
transform = Nystroem(gamma=gamma, random_state=random_state)
clf_sgd = SGDOneClassSVM(nu=nu, shuffle=True, fit_intercept=True, random_state=random_state, tol=1e-4)
pipe_sgd = make_pipeline(transform, clf_sgd)
pipe_sgd.fit(X_train)
y_pred_train_sgd = pipe_sgd.predict(X_train)
y_pred_test_sgd = pipe_sgd.predict(X_test)
y_pred_outliers_sgd = pipe_sgd.predict(X_outliers)
# 可视化决策边界
from sklearn.inspection import DecisionBoundaryDisplay
fig, ax = plt.subplots(figsize=(9, 6))
xx, yy = np.meshgrid(np.linspace(-4.5, 4.5, 50), np.linspace(-4.5, 4.5, 50))
X = np.concatenate([xx.ravel().reshape(-1, 1), yy.ravel().reshape(-1, 1)], axis=1)
DecisionBoundaryDisplay.from_estimator(clf, X, response_method="decision_function", plot_method="contourf", ax=ax, cmap="PuBu")
DecisionBoundaryDisplay.from_estimator(clf, X, response_method="decision_function", plot_method="contour", ax=ax, linewidths=2, colors="darkred", levels=[0])
DecisionBoundaryDisplay.from_estimator(clf, X, response_method="decision_function", plot_method="contourf", ax=ax, colors="palevioletred", levels=[0, clf.decision_function(X).max()])
# 绘制数据点
s = 20
b1 = plt.scatter(X_train[:, 0], X_train[:, 1], c="white", s=s, edgecolors="k")
b2 = plt.scatter(X_test[:, 0], X_test[:, 1], c="blueviolet", s=s, edgecolors="k")
c = plt.scatter(X_outliers[:, 0], X_outliers[:, 1], c="gold", s=s, edgecolors="k")
# 设置图表标题和标签
ax.set(title="One-Class SVM", xlim=(-4.5, 4.5), ylim=(-4.5, 4.5), xlabel=(f"error train: {y_pred_train[y_pred_train==-1].size} / {X_train.shape[0]}; " f"errors novel regular: {y_pred_test[y_pred_test==-1].size} / {X_test.shape[0]}; " f"errors novel abnormal: {y_pred_outliers[y_pred_outliers==1].size} / {X_outliers.shape[0]}"),)
# 显示图例
fig.legend([mlines.Line2D([], [], color="darkred", label="learned frontier"), b1, b2, c], ["learned frontier", "training observations", "new regular observations", "new abnormal observations"], loc="upper left")
plt.show()
通过上述代码,可以看到OneClassSVM和SGDOneClassSVM在异常检测任务上的表现。首先生成了训练数据和测试数据,然后使用OneClassSVM和SGDOneClassSVM进行训练和预测。还可视化了模型的决策边界,以便更好地理解模型是如何区分正常数据和异常数据的。最后,展示了模型在训练集和新观测值上的错误率,以评估模型的性能。
总的来说,使用支持向量机进行异常检测是一种有效的方法。通过选择合适的核函数和超参数,可以在各种数据集上获得良好的性能。此外,使用核近似和随机梯度下降的方法可以进一步提高模型的计算效率,使其适用于大规模数据集。
在实际应用中,可以根据具体问题选择合适的异常检测算法。对于线性可分的数据,可以使用线性SVM进行异常检测;对于非线性可分的数据,可以使用基于核技巧的SVM进行异常检测。此外,还可以尝试使用其他异常检测算法,如局部异常因子(LOF)和隔离森林等,以获得更好的性能。