大家好,我是菜菜卷!今天开始陆续和大家分享一些关于异常检测入门相关的实战项目(包括使用sklearn实现一些简单的机器学习模型或者使用pytorch实现简单的深度学习模型)
今天我们使用的模型是集成于sklearn内部实现的孤立森林算法。
什么是孤立森林(isolate forest)?
孤立森林是一种传统的异常检测机器学习算法,他属于
无监督学习
的boost 树模型,对于每棵子树来说,针对数据集的不同特征值,会随机挑选特征值取值范围内的一个随机值,然后将所有数据按照该特征的这个随机值划分为两部分(根据该特征值大于或者小于该随机值),这样我们就可以逐渐将所有的数据分开,
因为异常数据通常来说所占的比例都较少,所以一般使用较少的属性就可以将他们从正常数据中区分开来
,因此平均路径长度便可以作为是否是异常值的衡量指标(异常数据的平均路径长度会比正常数据更短)
所用数据集
数据集获取地址:
KDD1999Data
前往以上的地址,下载kddcup.data.gz即可。
该数据集是由若干正常和异常的数据分类,有41和特征和1个标签构成,因为后面我们只想对网页攻击方向的数据进行分析,所以要强调一下,第三个特征是表示异常的方向(即是哪种方面的异常,比如http还是其他)
项目所用环境
numpy 1.15.3
pandas 0.23.4
scikit-learn 0.19.1
matplotlib 2.2.2
大家可以使用pip或者conda自行安装项目环境,为保证顺利无bug复现结果,建议使用所示版本的包
项目实战
1、包的导入
首先我们先导入实验所需的第三方包
import time
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.ensemble import IsolationForest
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder
from sklearn.metrics import roc_auc_score
其中
time
可以用来记录时间和程序运行时间;
numpy
可以高效做矩阵运算,在数据处理中有广泛的运用;
pandas
可以快速方便的读入和处理数据的格式;
matplotlib
用于部分实验结果的可视化;
sklearn
是一个非常丰富的机器学习库,内部集成了基本的机器学习方法、数据集处理方法、模型衡量指标等功能。
2.使用pandas读入和处理数据
首先我们使用以下代码来读入数据:
data_path = r'dataset/kddcup.data.corrected'
columns = [str(i) for i in range(1, 42)]
columns.append('label')
df = pd.read_csv(data_path, sep=',', names=columns, index_col=None)
其中
columns
是我们给每个特征的命名,具体是什么都可以,只需要后续操作特征的时候可以对应上最开始的命名就可以了,这里我就简单的将最开始的41列命名为1-41的str类型数字,最后一列(第42列)命名为
'label'
;
names=columns
表示我们使用自定义的
columns
来命名数据中的42个列。
下面我们使用
print(df.shape)
看一下数据的大小,结果如下所示:
(4898431, 42)
说明我们的数据集有接近500w的数据,其中每个数据有42个属性(其中前41个位特征值,第42个是标签label)。
接下来我们简单的处理一下数据,假设目前我们仅关心与
http
相关的数据是否正常(第3列特征描述数据的分类),我们使用如下代码来挑选出数据集中所有和
http
相关的数据:
df = df[df['3'] == 'http']
df = df.drop('3', axis=1)
columns.remove('3')
其中
df['3'] == 'http'
用来判断数据
df
的第三个属性是否是
http
,是的话就是
True
,否的话就是
False
,所以
df = df[df['3'] == 'http']
实现的功能就是找到所有第三列属性是
http
的数据,因为在找到后,我们的第三列属性就无用了(因为都是
http
了),所以我们用
df = df.drop('3', axis=1)
将第三列属性去掉,下面我们再使用
print(df.shape)
看看数据的
shape
,结果如下所示:
(623091, 41)
我们可以发现,数据从原来的接近500w变成了现在的62w个,属性值也从42变成了41,说明我们以上操作成功了!
然后我们运行
print(df['label'].value_counts())
来观察一下
label
的取值,结果如下所示:
normal. 619046
back. 2203
neptune. 1801
portsweep. 16
ipsweep. 13
satan. 7
phf. 4
nmap. 1
Name: label, dtype: int64
从结果中我们可以发现,大多数数据都是正常的(
normal.
),但是也有一些其他异常的数据,我们本次的核心任务就是使用孤立森林模型来完成对数据正常与否的检测。
我们希望更详细的观察一些数据的情况,使用
print(df.head(5))
来显示前五个数据的详细信息:
1 2 4 5