孤立森林
异常的两个特点:异常数据只占很少量,异常数据特征值和正常数据差别很大。
孤立森林,不再是描述正常的样本点,而是要孤立异常点,由周志华教授等人于2008年在第八届IEEE数据挖掘国际会议上提出。
先了解一下该算法的动机。目前学术界对异常(anomaly detection)的定义有很多种,在孤立森林(iForest)中,异常被定义为“容易被孤立的离群点 (more likely to be separated)”,可以将其理解为分布稀疏且离密度高的群体较远的点。 在特征空间里,分布稀疏的区域表示事件发生在该区域的概率很低,因而可以认为落在这些区域里的数据是异常的。孤立森林是一种适用于连续数据(Continuous numerical data)的无监督异常检测方法,即不需要有标记的样本来训练,但特征需要是连续的。对于如何查找哪些点容易被孤立(isolated),iForest使用了一套非常高效的策略。在孤立森林中,递归地随机分割数据集,直到所有的样本点都是孤立的。在这种随机分割的策略下,异常点通常具有较短的路径。
在图 ( a ) (a) (a)和图 ( b ) (b) (b)中,可以看到,正常点 x i x_i xi需要更多次的分割才能被孤立,而异常点 x o x_o xo需要较少的分割次数就能被孤立。这里的分割方式采用的是,随机选择一个特征以及拆分的值(这个值位于该特征的最小值和最大值之间)。图 ( c ) (c) (c)展示了异常点的平均路径长度小于正常点的路径长度。
import numpy as np
import pandas as pd
import seaborn as sns
from sklearn.ensemble import IsolationForest
一维特征孤立森林
plt.figure(figsize=(8,6))
a1 = 5*np.random.rand(200) + 25
a2 = 10*np.random.rand(200) + 75
plt.hist(a1)
plt.hist(a2)
plt.show();
clf_isof = IsolationForest(n_estimators=100,
max_samples=200,
contamination=0.05,
max_features=1,
bootstrap=False,
n_jobs=2)
x_train = np.hstack([a1,a2,40,41,42]).reshape(-1,1)
clf_isof.fit(x_train)
df_temp = pd.DataFrame()
y_pred_train = clf_isof.predict(x_train)
df_temp['x_train'] = x_train.flatten()
df_temp['predict'] = y_pred_train
display (df_temp[df_temp['predict']==-1])
x_train | predict | |
---|---|---|
78 | 25.038350 | -1 |
93 | 29.980410 | -1 |
190 | 29.986068 | -1 |
199 | 29.987751 | -1 |
213 | 75.239520 | -1 |
220 | 84.803419 | -1 |
239 | 75.016752 | -1 |
248 | 75.323643 | -1 |
256 | 84.971489 | -1 |
273 | 84.593383 | -1 |
293 | 84.987898 | -1 |
300 | 84.428831 | -1 |
302 | 75.223079 | -1 |
304 | 84.886895 | -1 |
314 | 84.637187 | -1 |
315 | 75.191834 | -1 |
349 | 84.409206 | -1 |
350 | 84.899408 | -1 |
400 | 40.000000 | -1 |
401 | 41.000000 | -1 |
402 | 42.000000 | -1 |
plt.rcParams['xtick.labelsize'] = 10
plt.rcParams['ytick.labelsize'] = 10
plt.figure(figsize=(8,6))
df_after_ok = df_temp[df_temp['predict']==1]
plt.scatter(df_after_ok['x_train'],[1]*len(df_after_ok),c='green')
df_after_nok = df_temp[df_temp['predict']==-1]
plt.scatter(df_after_nok['x_train'],[1]*len(df_after_nok),c='red')
plt.show();
二维特征孤立森林
plt.figure(figsize=(8,6))
df1 = pd.DataFrame(np.random.normal(0,1,(200,2)))
display (df1.head())
plt.scatter(df1[0],df1[1],c='green')
plt.show()
0 | 1 | |
---|---|---|
0 | -0.115543 | -1.533842 |
1 | 0.770955 | 0.633411 |
2 | -1.300784 | 0.453213 |
3 | 1.564788 | -0.652716 |
4 | 0.477909 | 1.460001 |
clf_isof = IsolationForest(n_estimators=100,
max_samples=200,
contamination=0.05,
max_features=2,
bootstrap=False,
n_jobs=2)
x_train = df1
clf_isof.fit(x_train)
df_temp = pd.DataFrame()
y_pred_train = clf_isof.predict(x_train)
# df_temp['x_train'] = x_train.flatten()
df1['predict'] = y_pred_train
display (df1[df1['predict']==-1])
0 | 1 | predict | |
---|---|---|---|
14 | -2.135264 | 1.688260 | -1 |
34 | 1.428155 | -2.271243 | -1 |
61 | -0.020421 | -2.974580 | -1 |
78 | -0.899695 | -3.043032 | -1 |
82 | -1.807234 | 2.248468 | -1 |
104 | -2.432991 | -0.286251 | -1 |
114 | 2.209462 | 0.152440 | -1 |
125 | -0.698056 | -2.247866 | -1 |
145 | 2.235977 | 1.122833 | -1 |
148 | -2.073314 | 1.010237 | -1 |
plt.figure(figsize=(8,6))
df_after_ok = df1[df1['predict']==1]
plt.scatter(df_after_ok[0],df_after_ok[1],c='green')
df_after_nok = df1[df1['predict']==-1]
plt.scatter(df_after_nok[0],df_after_nok[1],c='red')
plt.show();