问题描述:当利用数据集进行模型训练前,一般需要先验证一下数据有没有异常点,当然缺省值也要关注,否则读取数据的时候得报错。这里我们先讨论数据集中的异常点检测问题。
当我们百度的时候,发现给出这几种方法,Z-score 方法,IQR(四分位数间距)方法,机器学习方法,One-Class SVM, 散点图,箱型图,组合方法,下面我们讨论一下可用性。
1. Z-score 方法
先塑造一个数据集,释放一个异常点,用来测试算法,波形图如下:
上python代码:
import pandas as pd
import numpy as np
from scipy import stats
# 读取数据
data = pd.read_csv('dataset.csv')
# 计算 z-score
z_scores = np.abs(stats.zscore(data))
# 设置阈值
threshold = 3
# 检测异常点
outliers = (z_scores > threshold).any(axis=1)
print("异常点的索引:", np.where(outliers)[0])
运行结果:异常点的索引: False []
然后我尝试改动 threshold变量值,但是很遗憾,改了好几轮还是没能成功,太精细化了。下面我们看一下啊第二种方法:
2. IQR(四分位数间距)方法
IQR 方法基于数据的四分位数计算异常点。通常,将低于 Q1 - 1.5 * IQR 或高于 Q3 + 1.5 * IQR 的数据点视为异常点。
Python 示例:
import pandas as pd
# 读取数据
data = pd.read_csv('dataset.csv')
data = np.array(data)
data = pd.DataFrame(data)#需要df使用quantile
# 计算 Q1 和 Q3
Q1 = data.quantile(0.25)
Q3 = data.quantile(0.75)
IQR = Q3 - Q1
# 设置异常点的条件
outliers = ((data < (Q1 - 1.5 * IQR)) | (data > (Q3 + 1.5 * IQR))).any(axis=1)
print("异常点的索引:", data[outliers].index.tolist())
得调参数1.5,我放到0.45并且异常值增大,效果如下:
异常点的索引: [67]
找到了点的位置,ok,下面将异常值变小,
异常点的索引: []
将系数调整为0.4,结果如下下:
异常点的索引: [53]
检测错误,还是效果不佳。测试下一种方法:
3. 机器学习方法
3.1 Isolation Forest
Isolation Forest 是一种基于树的模型,通过随机选择特征和切分点来孤立数据点。它适用于高维数据集。 iForest 属于Non-parametric和unsupervised的方法,即不用定义数学模型也不需要有标记的训练。对于如何查找哪些点是否容易被孤立(isolated),iForest使用了一套非常高效的策略。假设我们用一个随机超平面来切割(split)数据空间(data space),切一次可以生成两个子空间(详细拿刀切蛋糕一分为二)。之后我们再继续用一个随机超平面来切割每个子空间,循环下去,直到每个子空间里面只有一个数据点为止。直观上来讲,我们可以发现那些密度很高的簇是被切分很多次才会停止切割,但是那些密度很低的点很容易很早就停到一个子空间看了。
iForest 算法得益于随机森林的思想,与随机森林由大量决策树组成一样,iForest森林也由大量的二叉树组成,iForest 中的树叫 isolation tree,简称 iTree,iTree 树和决策树不太一样,其构建过程也比决策树简单,是一个完全随机的过程。
Python 示例:
import pandas as pd
from sklearn.ensemble import IsolationForest
# 读取数据
data = pd.read_csv('dataset.csv')
data = data1.reshape(1,-1)
# 创建 Isolation Forest 模型
iso_forest = IsolationForest(contamination=0.05) # contamination 是异常点的比例
outliers = iso_forest.fit_predict(data)
# -1 表示异常点,1 表示正常点
print("异常点的索引:", outliers, data[outliers == -1].tolist().index)
先安装一下sklean库:
pip install scikit-learn -i https://pypi.tuna.tsinghua.edu.cn/simple
实验结果:
异常点的索引: [1] <built-in method index of list object at 0x000002035D9D8B00>
无论我怎么更改系数,实验结果一直不变,不知问题出在哪里。
3.2 One-Class SVM
One-Class SVM 是一种基于支持向量机的模型,用于检测异常点。
Python 示例:
import pandas as pd
from sklearn.svm import OneClassSVM
# 读取数据
data = pd.read_csv('dataset.csv')
# 创建 One-Class SVM 模型
oc_svm = OneClassSVM(nu=0.05, kernel='rbf') # nu 是异常点的比例
outliers = oc_svm.fit_predict(data)
# -1 表示异常点,1 表示正常点
print("异常点的索引:", data[outliers == -1].index.tolist())
结果如下:
尽管将 nu=0.01还是有异常点
4. 可视化方法
4.1 散点图
对于二维数据集,散点图可以帮助直观地识别异常点。
Python 示例:
import pandas as pd
import matplotlib.pyplot as plt
# 读取数据
data = pd.read_csv('dataset.csv')
# 创建散点图
plt.scatter(data['feature1'], data['feature2'])
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.title('散点图')
# 可以在图上标记出检测到的异常点
plt.show()
4.2 箱型图
箱型图可以帮助识别离群点,尤其在一维数据中。
Python 示例:
import pandas as pd
import matplotlib.pyplot as plt
# 读取数据
data = pd.read_csv('dataset.csv')
# 创建箱型图
plt.boxplot(data['feature'])
plt.title('箱型图')
plt.ylabel('Feature Value')
plt.show()
遗憾的是还没检测出来。
总结
采用暴力简单方法直接输出吧,众所周知所谓的异常点直观感受就是这个点鹤立鸡群,与周围点显得格格不入,在直观感受就是突变或者曲线不够丝滑。如果用数学形式去描述就是梯度发生突变!OK,让我们先观测一下曲线的梯度图:
如果设定相应的阈值例如10,是不就可以最直接表现出来,当前保险起见您可以连续检测两个梯度为异常值时在判定为异常点。