【问题标题】:How to remove outliers from a dataset如何从数据集中删除异常值
【发布时间】:2011-06-14 19:30:01
【问题描述】:

我有一些关于美丽与年龄的多元数据。年龄范围为 20-40,间隔为 2 (20, 22, 24....40),对于每条数据记录,他们被赋予一个年龄和一个从 1-5 的美丽等级。当我绘制这些数据的箱线图(X 轴上的年龄,Y 轴上的美女评级)时,在每个框的胡须之外绘制了一些异常值。

我想从数据框本身中删除这些异常值,但我不确定 R 如何计算其箱线图的异常值。下面是我的数据可能是什么样子的示例。

【问题讨论】:

  • boxplot 函数不可见地返回异常值(以及其他统计信息)。尝试foo <- boxplot(...); foo 并阅读?boxplot 以了解输出。
  • 您应该根据您对@Prasad 回答的评论来编辑您的问题!
  • @aL3xa:在第二段的第一句。
  • 你能发个数据链接吗?

标签: r statistics outliers


【解决方案1】:

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

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

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

【讨论】:

  • 真的很优雅。谢谢。但是如果分布有多个模式,并且异常值确实很少且分散,则需要小心。
  • 如果您能够在数据集中获得它们的索引,那就太好了。您完成的方式将根据数据值进行过滤。如果箱线图也在做分组,则不一定相同的数据值会在每组中出现异常
  • 还有一点很重要,它不会改变数据集。这只是一种过滤方法。因此,如果您打算使用没有异常值的数据集,请将其分配给变量。例如result = x[!x %in% boxplot.stats(x)$out]
  • 只有一行代码并不一定意味着它很简单!理解一行代码并不总是那么容易,特别是对于初学者,并且没有 cmets。
  • @PM0087 并非总是如此,但在这种情况下,即使经过多年并且我几乎忘记了 R,它仍然读起来像一个干净的句子。“告诉我所有不是异常值的 x”
【解决方案2】:

好的,您应该将这样的内容应用到您的数据集。不要替换和保存,否则您将破坏您的数据!而且,顺便说一句,您应该(几乎)永远不要从数据中删除异常值:

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 能够在箱线图中输出异常值,我不应该进行这些中间计算。至于删除异常值,这只是一个作业。
  • 好的,我在这里遗漏了一些东西。您想从数据中删除异常值,因此可以使用boxplot 绘制它们。这是可以管理的,你应该标记@Prasad的答案,因为回答了你的问题。如果您想使用“异常值规则”q +/- (1.5 * H) 排除异常值,因此运行一些分析,然后使用此功能。顺便说一句,我是从头开始做的,没有谷歌搜索,所以我有机会用我的这个功能重新发明了轮子......
  • 你不应该在 stackoverflow 上问作业问题!
  • 这是否意味着我们也不应该回答它? =)
  • “离群值只是注定的”?不必要。它们可能来自测量错误,必须彻底审查。当异常值太大时,它可能意味着什么,或者没有那么多。这就是为什么(至少在生物学中)中位数通常比平均值更能说明总体。
【解决方案3】:

在绘制箱线图时使用outline = FALSE 作为选项(阅读帮助!)。

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

【讨论】:

  • 确实,这会从箱线图中删除异常值,但我想从数据框中删除异常值。
  • 我明白了,那么正如@Joshua 所说,您需要查看 boxplot 函数返回的数据(特别是列表中的 outgroup 项目)。
【解决方案4】:

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

我故意没有回答具体问题,因为我认为删除“异常值”是统计上的不当行为。我认为不将它们绘制在箱线图中是可以接受的做法,但是仅仅因为它们超过一定数量的标准偏差或一定数量的四分位数宽度而将它们删除是对观察记录的系统和不科学的破坏。

【讨论】:

  • 好吧,在不知道为什么问这个问题的情况下回避这个问题也不是一个好习惯。是的,从数据中删除“异常值”并不好,但有时您需要没有异常值的数据来执行特定任务。在我最近的一项统计任务中,我们必须可视化一个没有异常值的集合,以确定用于数据的最佳回归模型。就这样!
  • 我不认为您在这方面可能得到的“确定最佳回归模型”的建议特别有说服力。相反,如果您需要为那个含糊不清的目的删除异常值,那么我认为这对建议它的人的影响很差,而不是证明我的立场无效。
  • 当你知道你正在消除“噪音”时,我猜它是合法的。尤其是生理数据。
  • 是的。如果您有充分的理由相信信号是由一个单独的进程产生的,则有理由从数据中删除。
【解决方案5】:

我查找了与删除异常值相关的包,发现了这个包(令人惊讶地称为“异常值”!):https://cran.r-project.org/web/packages/outliers/outliers.pdf
如果您仔细阅读,您会看到去除异常值的不同方法,其中我发现rm.outlier 最方便使用,正如上面链接中所说: “如果异常值被统计测试检测并确认,此功能可以将其删除或替换为 样本均值或中位数”,这也是来自同一来源的用法部分:
"用法

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

参数
x 一个数据集,最常见的是一个向量。如果参数是一个数据框,那么异常值是 sapply 从每列中删除。 apply 应用相同的行为 当给定矩阵时。
fill 如果设置为 TRUE,则放置中位数或均值而不是异常值。否则, 离群值被简单地删除。
中值如果设置为 TRUE,则在离群值替换中使用中值而不是均值。 相反,如果设置为 TRUE,则给出相反的值(如果最大值具有最大差异 从平均值来看,它给出最小的,反之亦然) "

【讨论】:

  • 这看起来不错,但是如果您的数据框中有时间序列列,它会更改时间序列。
【解决方案6】:
x<-quantile(retentiondata$sum_dec_incr,c(0.01,0.99))
data_clean <- data[data$attribute >=x[1] & data$attribute<=x[2],]

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

【讨论】:

    【解决方案7】:

    不会:

    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
    

    很容易完成这项任务?

    【讨论】:

      【解决方案8】:

      添加到@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 &lt; quantile(mydata$var, probs=c(.01, .91))[1])mydata$var &lt; quantile(mydata$var, probs=c(.01, .99))[1])
      • 如果您有特定的理由使用第 91 个百分位而不是第 99 个百分位,您可以使用它。这只是一种启发式
      【解决方案9】:

      一种方法是

      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, ]
      

      【讨论】:

        【解决方案10】:

        异常值与峰值非常相似,因此峰值检测器可用于识别异常值。 here 描述的方法使用 z-scores 具有相当好的性能。页面下方的动画说明了异常值或峰值上的方法信号。

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

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

        【讨论】:

          【解决方案11】:

          试试这个。在函数中输入变量并将 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)
          }
          

          【讨论】:

          猜你喜欢
          • 2015-12-24
          • 2017-10-26
          • 1970-01-01
          • 2016-08-20
          • 2019-02-18
          • 2018-05-09
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多