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

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模型介绍

  • 24
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
基于支持向量机(Support Vector Machine, SVM)的网络流量异常检测是一种常用的机器学习方法。下面是一个简单的示例代码,用于演示如何使用Python中的scikit-learn库实现基于SVM的网络流量异常检测: ```python # 导入所需的库 import pandas as pd from sklearn import svm from sklearn.model_selection import train_test_split from sklearn.metrics import classification_report # 读取数据集 data = pd.read_csv('network_traffic.csv') # 划分特征和标签 X = data.drop('label', axis=1) y = data['label'] # 划分训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) # 创建SVM分类器 clf = svm.OneClassSVM(nu=0.1, kernel='rbf', gamma=0.1) # 训练模型 clf.fit(X_train) # 预测测试集 y_pred = clf.predict(X_test) # 打印分类报告 print(classification_report(y_test, y_pred)) ``` 在上述代码中,我们首先导入了所需的库,包括pandas用于数据处理,scikit-learn用于机器学习任务。然后,我们读取了包含网络流量数据的CSV文件,并将其划分为特征(X)和标签(y)。接下来,我们使用`train_test_split`函数将数据集划分为训练集和测试集。然后,我们创建了一个SVM分类器,并使用训练集对其进行训练。最后,我们使用测试集进行预测,并打印出分类报告。 请注意,上述代码仅为示例,实际应用中可能需要根据具体情况进行调整和优化。另外,还需要根据实际数据集的特点选择合适的SVM参数和核函数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

数智笔记

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

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

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

打赏作者

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

抵扣说明:

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

余额充值