异常检测系列:支持向量机(SVM)异常检测介绍

本文详细介绍了单类支持向量机(OCSVM)的概念,包括其基本思想、如何从SVM发展到OCSVM,以及如何通过异常得分定义异常值。文章还讨论了OCSVM对核函数和超参数的敏感性,并给出了一个建模过程实例,包括数据预处理、阈值确定和模型性能评估。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

img
分类问题通常使用监督学习算法解决,例如随机森林、支持向量机、逻辑回归器等。监督学习算法需要已知目标来构建模型。然而,通常情况下我们只看到正常数据模式而不是罕见事件。罕见事件的目标数据要么不可用,要么数量不足以进行模型训练。大多数时候,我们只观察到正常类而不是罕见类。一类支持向量机(OCSVM)解决了只有一个类可用的问题。它对正常类的属性进行建模。当将模型应用于可能包含异常数据的未知数据时,模型将能够检测到它们。

在本章中,我将解释支持向量机(SVM)的思想,以及如何将其发展成为一类支持向量机(OCSVM)。您将了解它如何定义异常值分数。

(A) 支持向量机(SVM)

支持向量机(SVM)是一种监督学习算法,可用于分类和回归问题。在1992-1995年期间,由AT&T贝尔实验室的Vladimir Vapnik和同事开发([1][2]),SVM已广泛应用于分类问题。

SVM具有非常好的特性。它可以创建非线性决策边界来分离两个类。它在高维空间中找到分离的方式非常优雅。不能通过直线分离的数据点首先投影到更高维的空间中,然后可以有一个“直”的超平面将一个类的数据点与另一个类的数据点分开。当超平面投影回原始空间时,它将成为一个非线性曲线。这可以在图(B)中理解。左侧的图显示蓝色和红色点不能使用任何直线分离。但是,如果将所有点投影到3D空间中,则结果变得线性可分。当数据投影回原始空间时,边界是一个非线性曲线。为什么在高维空间中分离成分变得更容易?这必须回到Vapnik-Chervonenkis(VC)理论[1]。它说将映射到更高维空间通常提供更大的分类能力。
img
图(B):(作者提供的图片)

在更高的空间中,支持向量机(SVM)通过虚线超平面找到支持向量,如图(B)所示。它被称为支持,因为它在特征空间中每个类的边缘上。它通过上述超平面的最大厚度找到两个类的最大分离。SVM允许一些软边界,使一些点位于支持向量之间的区域中,以避免过度拟合。

(B) 从SVM到单类SVM

由于只有一个类,如何构建算法来将一个类与另一个类分开?Schölkopf等人的单类SVM [4]将所有数据点从更高维度的空间中与原点分离,并最大化从该超平面到原点的距离。换句话说,原点是算法试图从正常类分离出来的类。图(B)展示了这个想法。在这里提到两种方法很有趣。Schölkopf等人[4]使用超平面进行分离,而Tax&Duin [5]应用球体进行分离。
img
(B)OVSVM

OVSVM是一种基于支持向量机的异常检测算法,它使用一个超平面来分离正常数据和异常数据。正常数据在超平面的一侧,而异常数据在另一侧。OVSVM的目标是找到一个最优的超平面,使得正常数据离超平面最远,而异常数据则尽可能靠近超平面。

© OCSVM如何定义异常得分?

OCSVM的异常得分是数据点到超平面的距离,如图(B)所示。这个距离也被称为相似度度量。相似度度量是通过N维相似度矩阵计算得出的(参见Aggarwal(2016)[6])。它是通过核函数计算得出的,例如径向基函数、线性函数、多项式函数或Sigmoid函数。径向基函数简单地计算输入x与固定点c之间的距离,例如ϕ(x)=f(‖x−c‖)

(D) OCSVM对RBF和超参数的选择敏感

OCSVM对核函数和一些超参数的选择非常敏感,性能可能会因选择而大幅变化。这种敏感性在[6]和[7]中有所记录。一个重要的超参数叫做nu,它是训练数据中数据点是异常点的概率。它是一个介于0和1之间的值。10%的nu意味着10%的数据可以被错误地分类为异常点,而支持边界上也有10%的数据。具体而言,nu是异常点比例和支持向量数量之间的权衡。

由于OCSVM对超参数非常敏感,解决方法是建立多个模型,并对预测结果进行平均,以获得稳定的结果。在后面的章节中,我将使用一系列nu值来生成模型,然后聚合预测结果。

(E) 建模过程

在本书中,我采用以下建模过程进行模型开发、评估和结果解释。

  1. 模型开发

  2. 阈值确定

  3. 正常组和异常组的描述性统计信息
    img
    (E.1) 第一步 — 构建模型

我们将使用数据生成过程(DGP)来模拟500个观测值和六个变量。我将异常值的百分比设置为5%。模拟数据有目标变量Y。我们将只使用X数据进行无监督模型OCSVM。


import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from pyod.utils.data import generate_data
contamination = 0.05 # percentage of outliers
n_train = 500       # number of training points
n_test = 500        # number of testing points
n_features = 6      # number of features
X_train, X_test, y_train, y_test = generate_data(
    n_train=n_train, 
    n_test=n_test, 
    n_features= n_features, 
    contamination=contamination, 
    random_state=123)

X_train_pd = pd.DataFrame(X_train)
X_train_pd.head()

前几个观测值如下所示:
img
图(E.1)以散点图的形式绘制了前两个变量。黄色点是异常值,紫色点是正常数据点。


# Plot
plt.scatter(X_train_pd[0], X_train_pd[1], c=y_train, alpha=0.8)
plt.title('Scatter plot')
plt.xlabel('x0')
plt.ylabel('x1')
plt.show()

img
图(D.1)

下面的代码指定并拟合了模型"ocsvm"。参数contamination=0.05声明了异常值的百分比为5%。这个参数不影响异常值得分的计算。如果没有指定,默认值为PyOD的10%。函数decision_function()计算观测值的异常值得分。函数predict()根据污染率分配"1"或"0"。语法.threshold_显示了分配的污染率的阈值。


from pyod.models.ocsvm import OCSVM
ocsvm = OCSVM(contamination=0.05)  
ocsvm.fit(X_train)


# Training data
y_train_scores = ocsvm.decision_function(X_train)
y_train_pred = ocsvm.predict(X_train)

# Test data
y_test_scores = ocsvm.decision_function(X_test)
y_test_pred = ocsvm.predict(X_test) # outlier labels (0 or 1)

def count_stat(vector):
    # Because it is '0' and '1', we can run a count statistic. 
    unique, counts = np.unique(vector, return_counts=True)
    return dict(zip(unique, counts))

print("The training data:", count_stat(y_train_pred))
print("The training data:", count_stat(y_test_pred))
# Threshold for the defined comtanimation rate
print("The threshold for the defined comtanimation rate:" , ocsvm.threshold_)

img
我们可以通过.get_params()来打印超参数的值:

ocsvm.get_params()

img
上述参数与核函数密切相关,因为OCSVM主要依赖于核函数的设置。默认的核函数是“rbf”,nu为0.5。“coef0”是核函数中的独立项,在“poly”和“sigmoid”中才有意义。如果核函数是多项式(“poly”),则“degree”确定多项式函数的次数。“max_iterint”设置模型优化的最大迭代次数。默认值为-1,表示没有限制,直到优化达到收敛。‘tol’设置停止准则的容忍度。catch_size指的是RAM的大小,决定了计算机上RAM的利用率。默认值为200(MB)。如果你有足够的RAM,可以将其设置为更高的值,如500(MB)或1000(MB)。通常情况下,您不需要担心这个参数。

(E.2) 第二步 - 确定一个合理的阈值

因为异常值分数衡量了异常值与正常数据点之间的偏差,我们可以使用异常值分数的直方图来了解其分布情况。直方图告诉我们具有高异常值分数的数据点的百分比,我们可以确定一个合理的阈值。图(E.2)建议在16.0处设置阈值,因为直方图中有一个自然的分割点。阈值确定了异常组的大小。


import matplotlib.pyplot as plt
plt.hist(y_train_scores, bins='auto')  # arguments are passed to np.histogram
plt.title("Histogram with 'auto' bins")
plt.xlabel('One-class SVM outlier score')
plt.show()

img
图(E.2)

(E.3) 第三步 — 展示正常组和异常组的描述统计

对正常组和异常组进行分析是展示模型的可靠性的关键步骤。我创建了一个名为descriptive_stat_threshold()的简短函数来展示关键指标。下面我只是采用了设定的异常率阈值。您可以测试一系列合理大小的异常组阈值。


threshold = ocsvm.threshold_ # Or other value from the above histogram

def descriptive_stat_threshold(df,pred_score, threshold):
    # Let's see how many '0's and '1's.
    df = pd.DataFrame(df)
    df['Anomaly_Score'] = pred_score
    df['Group'] = np.where(df['Anomaly_Score']< threshold, 'Normal', 'Outlier')

    # Now let's show the summary statistics:
    cnt = df.groupby('Group')['Anomaly_Score'].count().reset_index().rename(columns={'Anomaly_Score':'Count'})
    cnt['Count %'] = (cnt['Count'] / cnt['Count'].sum()) * 100 # The count and count %
    stat = df.groupby('Group').mean().round(2).reset_index() # The avg.
    stat = cnt.merge(stat, left_on='Group',right_on='Group') # Put the count and the avg. together
    return (stat)

descriptive_stat_threshold(X_train,y_train_scores, threshold)

img
表格(E.3)

这个指标对于模型评估非常重要。首先,让我们看一下百分比计数。在我们的案例中,它是5%。请记住,异常值组的大小是由阈值确定的。如果选择较高的阈值,它将减小。

其次,让我们检查正常组和异常组的特征均值。希望特征均值与任何先前的领域知识保持一致。例如,如果预期某个特征的均值在异常组中应该更高或更低,而结果相反,则应重新检查或删除该特征。当然,我们也可以使用新的见解来挑战先前的知识。您还需要使用特征名称标记特征,以便有效地展示。

最后,异常组的平均异常分数应该高于正常组的分数。您不需要过多解释分数。

因为我们的数据中有真实值,所以我们可以生成一个混淆矩阵来评估模型的性能。该模型表现良好,并在测试数据中识别出了所有25个异常值。


Actual_pred = pd.DataFrame({'Actual': y_test, 'Anomaly_Score': y_test_scores})
Actual_pred['Pred'] = np.where(Actual_pred['Anomaly_Score']< threshold,0,1)
pd.crosstab(Actual_pred['Actual'],Actual_pred['Pred'])

img
(F) 通过聚合多个模型实现模型稳定性

OCSVM是一种基于相似性的算法,对异常值敏感,容易出现过拟合问题。这种情况尤其因为第(D)节中的敏感性原因而更加明显。为了产生一个稳定的模型结果,我们应该建立多个具有不同参数的模型,然后聚合预测结果。

正如前面的章节所述,PyOD模块提供了四种方法来聚合结果:平均值、最大最大值(MOM)、最大平均值(AOM)和平均最大值(MOA)。让我们使用pip install combo来安装这些函数。请记住,您只需要使用一种聚合方法。下面的代码还会对输入数据进行标准化,尽管许多函数会自动进行标准化。

由于nu是最敏感的参数,让我们使用一系列广泛的nu值建立多个模型。总共会有11个模型。我们准备了11列的空数据框来存储这11个模型的预测结果。

from pyod.models.combination import aom, moa, average, maximization
from pyod.utils.utility import standardizer
from pyod.models.ocsvm import OCSVM

# Standardize data
X_train_norm, X_test_norm = standardizer(X_train, X_test)

# Test a range of nu
k_list = [0.01, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 0.99]
n_clf = len(k_list)
# Just prepare data frames so we can store the model results
train_scores = np.zeros([X_train.shape[0], n_clf])
test_scores = np.zeros([X_test.shape[0], n_clf])

# Modeling
for i in range(n_clf):
    k = k_list[i]
    ocsvm = OCSVM(nu=k,contamination=0.05)  
    ocsvm.fit(X_train_norm)
    # Store the results in each column:
    train_scores[:, i] = ocsvm.decision_function(X_train_norm) 
    test_scores[:, i] = ocsvm.decision_function(X_test_norm) 
# Decision scores have to be normalized before combination
train_scores_norm, test_scores_norm = standardizer(train_scores,test_scores)

十个模型的预测分数存储在“train_scores”中,并在“train_scores_norm”中进行了归一化。归一化是为了平均这十个预测结果。PyOD模块提供了四种聚合方法。您只需要使用一种方法来生成聚合结果。


# Combination by average
# The test_scores_norm is 500 x 10. The "average" function will take the average of the 10 columns. The result "y_by_average" is a single column: 
y_train_by_average = average(train_scores_norm)
y_test_by_average = average(test_scores_norm)
import matplotlib.pyplot as plt
plt.hist(y_train_by_average, bins='auto') # arguments are passed to np.histogram
plt.title("Combination by average")
plt.show()

img
图(F):训练数据平均预测值的直方图

图(F)中的直方图建议使用1.40作为阈值。我们可以通过表(F)中的聚合分数来推导描述性统计数据。它确定了25个数据点为异常值。读者应该对表(D.3)应用类似的解释。

descriptive_stat_threshold(X_train,y_train_by_average, 1.4)

img

表格(F)

(G) OCSVM算法摘要

  • 单类支持向量机(OCSVM)模型用于检测不属于正常类别的数据,以建模正常类别的属性。

  • 单类支持向量机(OCSVM)将数据点从原点分离到更高维空间,并最大化该超平面到原点的距离。换句话说,原点是算法试图将其与正常类别分离的类别。

参考文献

  • [1] Boser, B.E., Guyon, I.M. and Vapnik, V.N. (1992) A Training Algorithm for Optimal Margin Classifiers. Proceedings of the 5th Annual Workshop on Computational Learning Theory (COLT’92), Pittsburgh, 27–29 July 1992, 144–152.

  • [2] Cortes, Corinna; Vapnik, Vladimir (1995). “Support-vector networks” (PDF). Machine Learning. 20 (3): 273–297. CiteSeerX 10.1.1.15.9362. doi:10.1007/BF00994018. S2CID 206787478.

  • [3] Vapnik, Vladimir N (2000). The Nature of Statistical Learning Theory. Information Science and Statistics. Springer-Verlag. ISBN 978–0–387–98780–4.

  • [4] B. Schölkopf, J. C. Platt, J. Shawe-Taylor, A. J. Smola, and R. C. Williamson. Estimating the support of a high-dimensional distribution. Neural Computation, 13(7):1443–1471, 2001. 链接

  • [5] Tax, D.M., Duin, R.P. Support Vector Data Description. Machine Learning 54, 45–66 (2004). 链接

  • [6] Aggarwal, C. C. (2016). Outlier Analysis. Springer. ISBN: 978–3319475776

  • [7] L. M. Manevitz and M. Yousef. One-class SVMs for Document Classification. Journal of Machine Learning Research, 2: pp, 139–154, 2001.

异常检测系列文章导航

异常检测系列:异常检测基本介绍

异常检测系列:Histogram-based Outlier Score_HBOS算法

异常检测系列:基于经验累积分布的异常检测(ECOD)

异常检测系列:孤立森林(Isolation Forest)模型介绍

异常检测系列:主成分分析PCA异常值分数检测

异常检测系列:支持向量机(SVM)异常检测介绍

异常检测系列:单类支持向量机(OCSVM)

异常检测系列:高斯混合模型(GMM)

异常检测系列:局部异常因子(LOF)

异常检测系列:K最近邻算法KNN

异常检测系列:基于聚类的局部异常因子(CBLOF)

异常检测系列:基于极限梯度提升的异常检测(XGBOD)

异常检测系列:AutoEncoder模型介绍

<think>好的,我现在需要帮助用户了解如何使用支持向量机SVM)进行数据异常检测。首先,我得回顾一下SVM的基本原理,因为异常检测通常是基于分类或离群点检测的方法。SVM本身主要是用于分类任务,但如何应用到异常检测呢? 根据用户提供的引用,特别是引用[1]和[2],SVM的核心是找到一个超平面来最大化间隔,而核函数可以将数据映射到高维空间处理非线性问题。那异常检测可能和一分类SVM有关,或者使用支持向量数据描述(SVDD)?我需要确认这些方法。 首先,SVM异常检测中的常见方法可能包括One-Class SVM,这是专门用于无监督异常检测的。它的原理是找到一个能够包含大部分正常数据的区域,而将边界的点视为异常。这需要用到核函数,如引用[2]提到的核技巧,处理非线性数据。 接下来,我需要整理步骤:数据预处理、模型选择、核函数调参、训练模型、异常判定。对于案例,可以引用用户提到的Scikit-learn库,因为引用[3]中有使用该库的示例。例如,使用OneClassSVM类,对合成数据进行训练,然后预测异常点。 然后,注意事项部分需要提到特征标准化,因为SVM对尺度敏感;样本不平衡可能需要调整nu参数;核函数的选择影响结果,比如RBF核适合非线性情况。这些点需要结合引用中的信息,确保正确性。 关于应用场景,可以举网络入侵检测、工业质检、金融欺诈等,这些都是常见的异常检测场景,用户可能感兴趣的实际例子。 可能还需要考虑如何评估模型效果,比如使用准确率、召回率等指标,但异常检测中常用F1分数或AUC,不过用户的问题可能更关注方法和案例,所以这部分可能不需要深入,除非用户后续提问。 现在,我需要验证这些思路是否正确。例如,One-Class SVM是否属于SVM的应用之一?是的,Scikit-learn中的确有此实现。另外,SVDD是另一种方法,但用户可能更熟悉One-Class SVM,所以重点放在这里。 然后,代码示例部分需要展示如何用Python实现,使用合成数据,预处理,训练模型,预测,并可视化结果。这能帮助用户直观理解。需要注意代码中的关键参数,比如kernel='rbf',nu=0.05等,解释它们的作用。 最后,生成相关问题需要考虑用户可能的后续疑问,比如参数调优、与其他算法比较、处理高维数据等。这些问题应基于当前回答的内容,引导用户进一步学习。 总结一下,我需要分步骤解释方法,提供案例代码,注意事项,应用场景,并生成相关问题。确保引用正确,比如引用[2]提到核函数的作用,引用[3]中的代码实例,但用户的问题是关于异常检测,所以可能需要调整引用部分,确保相关性。</think>### 使用支持向量机SVM)进行数据异常检测的方法 #### 1. **核心原理** - **SVM异常检测**通常基于**One-Class SVM**(一分类支持向量机),其目标是找到一个超平面,将**正常数据**尽可能包含在高维空间的一个紧凑区域中,而将偏离该区域的样本视为异常[^1][^2]。 - 通过核函数(如RBF核)将数据映射到高维空间,解决非线性可分问题,增强对复杂数据分布的拟合能力。 #### 2. **实施步骤** 1. **数据预处理**:标准化或归一化数据(SVM对特征尺度敏感)。 2. **模型选择**:使用`OneClassSVM`(Scikit-learn实现),设定核函数和参数。 3. **训练模型**:仅用正常数据训练模型,学习正常数据的分布边界。 4. **异常判定**:通过`decision_function`或`predict`输出样本的异常得分,得分低于阈值的判为异常。 #### 3. **案例:工业质检异常检测** **代码示例**: ```python from sklearn.svm import OneClassSVM from sklearn.datasets import make_blobs import matplotlib.pyplot as plt import numpy as np # 生成合成数据(正常样本+少量异常) X, _ = make_blobs(n_samples=300, centers=1, cluster_std=0.5, random_state=42) X_outliers = np.random.uniform(low=-6, high=6, size=(20, 2)) X_total = np.vstack([X, X_outliers]) # 训练One-Class SVM model = OneClassSVM(kernel='rbf', nu=0.05) # nu控制异常点比例上限 model.fit(X_total) y_pred = model.predict(X_total) # 异常点返回-1 # 可视化结果 plt.scatter(X_total[:,0], X_total[:,1], c=y_pred, cmap='coolwarm') plt.title('One-Class SVM异常检测结果') plt.show() ``` #### 4. **关键参数与调优** - **`nu`**:控制异常点比例上限(取值0.01~0.5),值越小对异常越敏感。 - **`kernel`**:选择核函数(如`rbf`、`poly`),需通过交叉验证调整`gamma`或`degree`参数[^2]。 #### 5. **注意事项** - **特征工程**:需结合领域知识选择与异常相关的特征。 - **样本不平衡**:若异常样本极少,可结合过采样或半监督方法。 - **结果解释**:需结合实际场景分析异常原因,避免误判。 #### 6. **应用场景** - **网络入侵检测**:识别流量中的异常行为[^3]。 - **金融欺诈检测**:发现信用卡异常交易。 - **工业设备监控**:预测机械故障前的异常信号。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

数智笔记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值