关于异常值的处理是特征处理过程一项比较重要的环节,异常值的存在会对数据敏感的模型的预测结果造成偏差,因此对异常值的处理显得尤为的重要。
异常值有单变量处理,多变量处理之分,单变量处理相对比较容易,盒图就是很好的工具,多变量的异常值处理就相对比较麻烦,因为对于异常值的定义不如单变量那么简单明确。
- 单变量
以iris数据集为例子
# 加载数据
data(iris)
# 探索iris第一列的数据分布
plot(density(iris[, 1]))
如图示,数据分布大致符号正态分布,可以利用正态分布的5%概率原则来定义异常值超过或者低于均值两个标准差的值可划分为异常值。
mean(iris[, 1]) + 2 * sd(iris[, 1])
# [1] 7.499466
mean(iris[, 1]) - 2 * sd(iris[, 1])
# [1] 4.187201
结果显示落在 [4.187201, 7.499466] 区间外的值都被划分为了异常值,这里选取判断异常的阈值等于均值加减两倍的标准差,那么根据正态分布的规律有5%的概率会将正确的值误判断为异常值。
summary(iris[, 1])
# Min. 1st Qu. Median Mean 3rd Qu. Max.
# 4.300 5.100 5.800 5.843 6.400 7.900
# 超过最大阈值的数目
length(iris[, 1][iris[, 1]> 7.499466])
# [1] 6
# 超过最小阈值的数目
length(iris[, 1][iris[, 1]< 4.187201])
# [1] 0
如统计结果所示,有6个数据超出了最大阈值,那么这些值可以定义为异常值,当然这样判断异常的方法存在一定问题,因为我们假设了该数据分布是符合正态分布的,不过从数据分布图也可大致断定数据符合正态分布,因此我们才能有一定理论依据来断定异常值, 这里可以用 Shapiro-Wilk test来验证一下数据分布是否符合正态。
shapiro.test(iris[, 1])
# Shapiro-Wilk normality test
#
# data: iris[, 1]
# W = 0.97609, p-value = 0.01018
P 值等于0.01 < 0.05 则,拒绝原假设,接受备选假设。数据不符合正态分布,看来我们肉眼欺骗了我们,让我们觉得中间高两边低的数据分布线都是正态的分布,那么由此我们可能得到了错误的异常值。
那只能换一种更通用的方法来检测异常值了,盒图就是个不错的选择。
boxplot(iris[, 1])
盒图最大观测为Q3 + 1.5 * IQR, 最小观测为Q1 - 1.5 * IQR, 可以重新计算一下合理观测值的区间。
quantile(iris[, 1], 0.75) + 1.5 * IQR(iris[, 1])
# 75%
# 8.35
# quantile(iris[, 1], 0.25) - 1.5 * IQR(iris[, 1])
# 25%
# 3.15
新区间为 [3.15 , 8.35],数据的所有值均包含在区间当中,故盒图中并没有显示出异常值的存在。
- 多变量
关于多变量的异常检测较为复杂,主要是对何为异常值的定义不是那么确切,为了简化问题,这里只讨论二维数据。
# 加载数据集
data(women)
plot(women, xlab = "Height (in)", ylab = "Weight (lb)",
main = "women data: American women aged 30-39")
图中显示美国30-39岁的女性体重随身高的变化的散点图,图很明显表现出体重和身高之间的线性关系,这里体重的单位是磅,身高单位是英寸,看起来不怎么习惯,可以转换一下。
with(women, plot(height * 2.54, weight * 0.4536, xlab = "Height (cm)", ylab = "Weight (kg)", main = "women data: American women aged 30-39"))
这里在数据中添加两个点(180, 55), (150, 70)
points(180, 55, col = "green")
points(150, 70, col = "red")
图中很明显的看出该两点远远偏离了正常数据的变化,对该两点赋予现实含义,一个身高为180cm的女性只有55公斤体重,一个体重有70公斤的女性只有150cm的身高,看似显示为异常的数据,赋予现实意义时候缺发现并无不合理的地方里,前者可能是模特,后者是土肥圆。如果对于数据本身加一个限定条件,正常女性体重身高数据集,那么异常的存在就有背常态了。
结论:单纯的根据数据处理的技术来检测异常,只是单纯的对某个特定的数据集中找出超过阈值过多的值,必须要结合具体数据集特征的现实意义,和要建立的预测模型的响应变量来综合确定异常值的去留问题,而不能单纯的根据数据来判定,由此可见高维度的异常检测存在太多的不确定性因素。