如何从数据集中删除离群值


98

我有一些关于年龄与美丽的多元数据。年龄范围为20至40,间隔为2(20,22,24 .... 40),对于每条数据记录,年龄和美容等级均为1-5。当我对这些数据进行箱形图绘制(X轴上的年龄,Y轴上的美容等级)时,每个框的晶须外都绘制了一些离群值。

我想从数据框中删除这些离群值,但是我不确定R如何计算其箱形图的离群值。以下是我的数据可能显示的示例。 在此处输入图片说明


2
boxplot函数不可见地返回异常值(以及其他统计信息)。尝试foo <- boxplot(...); foo阅读?boxplot以了解输出。
约书亚·乌尔里希

您应该根据对@Prasad答案的评论来编辑问题!
aL3xa 2011年

@ aL3xa:在第二段的第一句中。
约书亚·乌尔里希


您可以发送数据链接吗?
wordforthewise

Answers:


119

好的,您应该对数据集应用类似的方法。请勿替换并保存,否则将破坏您的数据!而且,顺便说一句,您(几乎)永远不要从数据中删除异常值:

remove_outliers <- function(x, na.rm = TRUE, ...) {
  qnt <- quantile(x, probs=c(.25, .75), na.rm = na.rm, ...)
  H <- 1.5 * IQR(x, na.rm = na.rm)
  y <- x
  y[x < (qnt[1] - H)] <- NA
  y[x > (qnt[2] + H)] <- NA
  y
}

要查看实际效果:

set.seed(1)
x <- rnorm(100)
x <- c(-10, x, 10)
y <- remove_outliers(x)
## png()
par(mfrow = c(1, 2))
boxplot(x)
boxplot(y)
## dev.off()

再一次,您绝不应该自己执行此操作,离群值只是意味着!=)

编辑:na.rm = TRUE默认添加。

EDIT2:删除了quantile功能,添加了下标,因此使功能更快!=)

在此处输入图片说明


谢谢您的帮助!我想如果R能够在箱线图中输出离群值,那么我就不必进行这些中间计算。至于删除异常值,这仅是一项任务。
Dan Q

3
好的,我在这里缺少什么。您要从数据中删除离群值,因此可以使用绘制它们boxplot。这是可以管理的,既然已经回答了您的问题,那么您应该标记@Prasad的答案。如果要使用“异常值规则”排除异常值q +/- (1.5 * H),请运行一些分析,然后使用此功能。顺便说一句,我是从头开始的,没有谷歌搜索,所以我有可能用我的这个功能重新发明了轮子……
aL3xa 2011年

10
您不应该在stackoverflow上询问分配问题!
hadley 2011年

7
这是否意味着我们也不应该回答?=)
aL3xa 2011年

5
“离群值是注定的”?不必要。它们可能来自测量错误,必须进行彻底检查。当离群值太大时,可能意味着某些事情,或者没有太大意义。这就是为什么(至少在生物学上)中位数通常表示的是人口多于平均值。
罗德里戈

132

没有人发布最简单的答案:

x[!x %in% boxplot.stats(x)$out]

另请参阅:http//www.r-statistics.com/2011/01/how-to-label-all-the-outliers-in-a-boxplot/


4
真的很优雅。谢谢。但是,如果分发具有多个模式且离群值确实很少且分散,则需要小心。
KarthikS 2015年

如果能够在数据集中获取它们的索引,那将是非常不错的。完成的方式将根据数据值进行过滤。如果箱线图也正在进行分组,则每个组中不一定有相同的数据值
亚当

2
同样重要的是要提到它不会更改数据集。这只是一种过滤方法。因此,如果您打算使用没有异常值的数据集,则将其分配给变量。例如result = x[!x %in% boxplot.stats(x)$out]
Victor Augusto

仅使用一行代码并不一定意味着它很简单!尤其是对于初学者来说,没有注释就很难理解单行代码。
PeyM87

29

使用outline = FALSE时,你做的箱线图作为一个选项(阅读帮助!)。

> m <- c(rnorm(10),5,10)
> bp <- boxplot(m, outline = FALSE)

在此处输入图片说明


4
确实,这将从箱线图本身中删除异常值,但是我想从数据框中删除异常值。
Dan Q

2
我看到了,然后正如@Joshua所说,您需要查看boxplot函数返回的数据(尤其是列表中的outgroup项目)。
Prasad Chalasani 2011年

16

boxplot函数返回用于进行绘图的值(实际上是由bxp()完成:

bstats <- boxplot(count ~ spray, data = InsectSprays, col = "lightgray") 
#need to "waste" this plot
bstats$out <- NULL
bstats$group <- NULL
bxp(bstats)  # this will plot without any outlier points

我故意不回答具体问题,因为我认为删除“异常值”是一种统计错误。我认为不将它们绘制在箱线图中而是可以接受的做法是,仅由于它们超出了一些标准偏差或一定数量的四分位数宽度而将其删除是对观测记录的系统性和不科学的处理。


4
好吧,在不知道为什么提出问题的情况下回避问题也不是一种好习惯。是的,从数据中删除“异常值”不是一件好事,但有时您需要的数据没有特定任务的异常值。在我最近进行的统计工作中,我们必须可视化一个没有异常值的集合,以确定用于数据的最佳回归模型。在那里!
Alex Essilfie 2012年

4
我不认为您在“确定最佳回归模型”方面可能会特别有说服力。相反,如果您需要出于这个模糊的目的删除异常值,那么我认为这对建议的人反映不佳,而不是证明我的立场无效。
IRTFM 2012年

当您知道要消除“噪声”时,我想它是合法的。特别是在生理数据中。
roscoe1895 '19

是。如果您有充分的理由相信一个单独的过程会产生信号,则有理由从数据中删除该信号。
IRTFM '19

9

我抬起头,对相关移除离群包,发现这个包(令人惊讶的叫“异常值”!):https://cran.r-project.org/web/packages/outliers/outliers.pdf
如果你通过它,你看到了消除异常值的不同方法,其中找到了rm.outlier最方便的一种使用方法,正如上面链接中所述:“如果通过统计检验检测到并确认了异常值,则此功能可以将其删除或替换为样本均值或中位数”这也是来自同一来源的用法部分:
用法

rm.outlier(x, fill = FALSE, median = FALSE, opposite = FALSE)

参数
x 数据集,最常见的是向量。如果参数是一个数据框,则通过应用从每列中移除异常值。给定矩阵时,通过apply应用相同的行为。
fill 如果设置为TRUE,则放置中位数或均值而不是离群值。否则,将异常值简单地删除。
中位数 如果设置为TRUE,则使用中位数代替异常值替换中的均值。相反,如果设置为TRUE,则给出相反的值(如果最大值与均值之差最大,则给出最小值,反之亦然)“


这似乎很棒,但是如果数据框中有一个时间序列列,它将更改时间序列。
PeyM87

7
x<-quantile(retentiondata$sum_dec_incr,c(0.01,0.99))
data_clean <- data[data$attribute >=x[1] & data$attribute<=x[2],]

我发现这非常容易消除异常值。在上面的示例中,我只是提取2%到98%的属性值。


5

不会:

z <- df[df$x > quantile(df$x, .25) - 1.5*IQR(df$x) & 
        df$x < quantile(df$x, .75) + 1.5*IQR(df$x), ] #rows

轻松完成此任务?


4

除了@sefarkas的建议并使用分位数作为临界值,人们可以探索以下选项:

newdata <- subset(mydata,!(mydata$var > quantile(mydata$var, probs=c(.01, .99))[2] | mydata$var < quantile(mydata$var, probs=c(.01, .99))[1]) ) 

这将删除超出第99个分位数的点。应该像aL3Xa所说的保持异常值一样小心。仅应将其删除才能获得另一种保守的数据视图。


0.91还是0.99?如在mydata$var < quantile(mydata$var, probs=c(.01, .91))[1])mydata$var < quantile(mydata$var, probs=c(.01, .99))[1])
Komal Rathi's

如果有特定的原因使用第91个百分点而不是第99个百分点,则可以使用它。这只是一种启发式
KarthikS

1

做到这一点的一种方法是

my.NEW.data.frame <- my.data.frame[-boxplot.stats(my.data.frame$my.column)$out, ]

要么

my.high.value <- which(my.data.frame$age > 200 | my.data.frame$age < 0) 
my.NEW.data.frame <- my.data.frame[-my.high.value, ]

0

离群值与峰非常相似,因此峰值检测器可用于识别离群值。这里描述的方法使用z分数具有相当好的性能。页面下方的动画部分说明了发出异常值或峰值的方法。

峰值并不总是与异常值相同,但是它们经常相似。

此处显示一个示例:通过串行通讯从传感器读取此数据集。偶尔的串行通讯错误,传感器错误或同时导致这两者会导致重复的,明显错误的数据点。在这一点上没有统计价值。可以说它们不是异常值,而是错误。Z分数峰值检测器能够在虚假数据点上发出信号,并生成干净的结果数据集:在此处输入图片说明


-1

试试这个。将变量输入函数中,然后将o / p保存在包含已删除异常值的变量中

outliers<-function(variable){
    iqr<-IQR(variable)
    q1<-as.numeric(quantile(variable,0.25))
    q3<-as.numeric(quantile(variable,0.75))
    mild_low<-q1-(1.5*iqr)
    mild_high<-q3+(1.5*iqr)
    new_variable<-variable[variable>mild_low & variable<mild_high]
    return(new_variable)
}

请在回答中添加一些解释。请参阅“ 如何回答”
ejderuby
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.