R语言中的离群值检测和处理

标签:
r语言大数据分析数据分析师数据科学家数据挖掘 |
数据中的离群值往往会扭曲预测结果并影响模型精度,回归模型中离群值的影响尤其大,因此我们需要对其进行检测和处理。
离群值检测的重要性
处理离群值或者极端值并不是数据建模的必要流程,然而,了解它们对预测模型的影响也是大有裨益的。数据分析师们需要自己判断处理离群值的必要性,并结合实际问题选取处理方法。那么,检测离群值的重要性体现在哪儿呢?其实,由于离群值的存在,模型的估计和预测可能会有很大的偏差或者变化。我们用汽车数据来说明这个现象。
我将用包含和不含离群值的汽车数据来建立一个简单的线性回归模型,以此阐述离群值的影响。为了更好的区分它的效应,我在原始数据集中人为地加入了极端值,然后利用线性归回做预测。
# 给数据集插入离群值
cars1 <- cars[1:30,
cars_outliers <- data.frame(speed = c(19, 19, 20,
20, 20),
cars2 <- rbind(cars1,
cars_outliers)
# 绘制包含离群值的数据建模结果
par(mfrow = c(1, 2))
plot(cars2$speed, cars2$dist, xlim = c(0, 28), ylim=c(0,
230),
abline(lm(dist ~ speed, data = cars2), col = "blue", lwd = 3, lty =
2)
# 绘制原始数据建模加过,留意回归线斜率的变化
plot(cars1$speed, cars1$dist, xlim = c(0, 28), ylim = c(0,
230),
abline(lm(dist ~ speed, data = cars1), col = "blue", lwd = 3, lty =
2)
结果如下
http://www.cda.cn/uploadfile/image/20170219/20170219210406_21273.png
留意一下移除离群值后拟合线的斜率变化。如左图所示,如果用包含离群值的数据训练模型,我们预测结果在速度很快的数据上会有很大的误差,因为回归线非常陡峭。
检测离群值
1. 单变量检测法
给定一个连续变量后,离群值可以认为是哪些超出1.5倍四分位距的观测点。四分位距(Inter Quartile Range, a.k.a IQR)是0.25分位数和0.75分位数的差,我们可以通过箱线图来检测离群点,在须轴以外的点就是。
url <-
"http://rstatistics.net/wp-content/uploads/2015/09/ozone.csv"
# 备用数据源:
https://raw.githubusercontent.com/selva86/datasets/master/ozone.csv
inputData <- read.csv(url)
outlier_values <-
boxplot.stats(inputData$pressure_height)$out
boxplot(inputData$pressure_height, main="Pressure Height",
boxwex=0.1)
mtext(paste("Outliers: ", paste(outlier_values, collapse=", ")),
cex=0.6)
2. 双变量检测法
如果有两个变量X和Y,X是分类变量而Y是连续变量,可以绘制在X的不同类别上Y的箱线图来检测离群值。
url <-
"http://rstatistics.net/wp-content/uploads/2015/09/ozone.csv"
ozone <- read.csv(url)
# Month和Day_of_Week是分类变量
boxplot(ozone_reading ~ Month, data=ozone, main="Ozone reading
across months")
boxplot(ozone_reading ~ Day_of_week, data=ozone, main="Ozone
reading for days of week")
箱线图如下:
http://www.cda.cn/uploadfile/image/20170219/20170219210317_91845.png
上图我们发现每个月的ozone_reading数据有明显变化,但在周内每天的区别并不明显。每一个类别中,在箱线图须轴以外的店就是离群值。
如果X和Y都是连续变量,我们可以将X离散化
boxplot(ozone_reading ~ pressure_height,
data=ozone,
boxplot(ozone_reading ~ cut(pressure_height,
pretty(inputData$pressure_height)),
结果如下
http://www.cda.cn/uploadfile/image/20170219/20170219210243_35598.png
离散化处理后,你会发现被判定为离群值的点更少,并且ozone_reading随着pressure_height的增加而变化的趋势愈发明确了。
3. 多元模型检测法
仅凭一个特征就判定一个观测值是离群点可能并不科学。利用多个特征的信息来判断个体是否是离群值会更好,这就需要使用Cook距离。
Cook距离可以衡量一个给定的回归模型是否只受单个变量X的影响。Cook距离会极端每一个数据点对预测结果的影响。对于每个观测i,Cook距离会衡量包含i与不包含i时,Y的拟合值的变化,这样我们就知道了i对拟合结果的影响了。
观测i的Cook距离 计算公式如下:
http://www.cda.cn/uploadfile/image/20170219/20170219210219_98536.png
其中:
是使用所有观测计算的第j个y的拟合值
是使用除观测i外所有观测计算的第j个y的拟合值
是均方误差
是回归模型的系数个数
mod <- lm(ozone_reading ~ ., data=ozone)
cooksd <- cooks.distance(mod)
影响评估
一般来说,如果某个观测的Cook距离比平均距离大4倍,我们就可以认为这个点是离群点,当然这不是一个非常死板的判定条件。
plot(cooksd, pch="*", cex=2, main="Influential Obs by Cooks
distance")
abline(h = 4*mean(cooksd, na.rm=T), col="red")
text(x=1:length(cooksd) 1, y=cooksd,
labels=ifelse(cooksd>4*mean(cooksd,
na.rm=T),names(cooksd),""), col="red")
结果如下:
http://www.cda.cn/uploadfile/image/20170219/20170219210117_18076.png
现在让我们从原始数据集中找出那些影响力特别大的观测点吧。如果你把它们逐一挑出来了,你就能发现为何它们会有这么大的影响力了——这些观测的在某些变量上的取值过于极端了。
influential
head(ozone[influential, ])
#>
#>
19
#>
23
#>
58
#>
133
#>
135