【问题标题】:Ignore outliers in ggplot2 boxplot忽略ggplot2箱线图中的异常值
【发布时间】:2019-06-03 13:03:58
【问题描述】:

如何忽略 ggplot2 boxplot 中的异常值?我不只是希望它们消失(即 outlier.size=0),而是希望它们被忽略,以便 y 轴缩放以显示第 1/3 个百分位数。我的异常值导致“盒子”缩小到几乎是一条线。有什么技术可以解决这个问题吗?

编辑 这是一个例子:

y = c(.01, .02, .03, .04, .05, .06, .07, .08, .09, .5, -.6)
qplot(1, y, geom="boxplot")

【问题讨论】:

  • 一些示例数据和一个可重现的示例将使您更容易为您提供帮助。
  • 我的文件是 200 兆!只需在第一个和第三个分位数之间有很多数据点和一些异常值(你只需要 1 个)的任何数据集。如果离群值远离第 1/3 个,则框必然会缩小以容纳离群值
  • 是的,这就是我的想法。制作这样一个数据集并使用 dput() 将其与您使用的 ggplot() 语句一起发布到此处。帮助我们为您提供帮助。
  • 您不能将 y 轴限制更改为“放大”您感兴趣的 y 轴部分吗?
  • 让我看看....哦,是的,对不起。只需对数据执行fivenum() 即可提取IIRC 用于箱线图上铰链和下铰链的内容,并在@Ritchie 显示的scale_y_continuous() 调用中使用该输出。使用 R 和 ggplot 提供的工具,这可以很容易地自动化。如果您还需要包括胡须,请考虑使用boxplot.stats() 来获取胡须的上限和下限,然后在scale_y_continuous() 中使用。

标签: r ggplot2


【解决方案1】:

使用geom_boxplot(outlier.shape = NA) 不显示异常值,使用scale_y_continuous(limits = c(lower, upper)) 更改轴限制。

一个例子。

n <- 1e4L
dfr <- data.frame(
  y = exp(rlnorm(n)),  #really right-skewed variable
  f = gl(2, n / 2)
)

p <- ggplot(dfr, aes(f, y)) + 
  geom_boxplot()
p   # big outlier causes quartiles to look too slim

p2 <- ggplot(dfr, aes(f, y)) + 
  geom_boxplot(outlier.shape = NA) +
  scale_y_continuous(limits = quantile(dfr$y, c(0.1, 0.9)))
p2  # no outliers plotted, range shifted

实际上,正如 Ramnath 在他的回答中所表明的那样(Andrie 在 cmets 中也是如此),在通过 coord_cartesian 计算统计数据之后裁剪比例更有意义。

coord_cartesian(ylim = quantile(dfr$y, c(0.1, 0.9)))

(您可能仍需要使用scale_y_continuous 来修复轴断裂。)

【讨论】:

  • 所以我必须计算下限/上限 - 也许通过计算第 1/3 个百分位数?这意味着没有自动魔术方法告诉 gg-plot2 忽略异常值并智能扩展?
  • 小心使用 scale_y_continuous(limits=...) 这将删除超出限制的数据,然后执行统计计算。换句话说,平均值和其他摘要将受到影响。如果这是你想要的,那就太好了。另一种方法是使用 coord_cartesian(limits=...) - 这会“放大”而不删除数据或影响摘要。
  • @Andrie - 谢谢!我不希望平均值和其他摘要受到影响。
  • coord_cartesian() 不能很好地与coord_flip() 配合使用,以我的经验,所以我更喜欢scale_y_continuous()
  • 这是最好的解决方案。我想隐藏异常值的原因是因为我也在用 geom_jitter 绘制抖动点。在这种情况下,异常值只是妨碍了它,让它看起来比应该有的点多。
【解决方案2】:

这是使用 boxplot.stats 的解决方案

# create a dummy data frame with outliers
df = data.frame(y = c(-100, rnorm(100), 100))

# create boxplot that includes outliers
p0 = ggplot(df, aes(y = y)) + geom_boxplot(aes(x = factor(1)))


# compute lower and upper whiskers
ylim1 = boxplot.stats(df$y)$stats[c(1, 5)]

# scale y limits based on ylim1
p1 = p0 + coord_cartesian(ylim = ylim1*1.05)

【讨论】:

  • +1 用于自动计算,+1 用于使用 coord_cartesian 进行缩放而不是排除数据
  • @Ben - 你有两个帐户? =) @Ramnath - 这是一个非常优雅的解决方案
  • 使用上述方法,限制可能会因一侧的小极端和另一侧的大极端而产生偏差,例如ylim &lt;- c(-0.1, 1000) * 1.05[1] 0.105 1050。要在平均值附近获得相等的限制,您可以使用ylim + c(-0.05, 0.05) * diff(ylim) / 2。在我看来更漂亮。
  • @Ramnath $stats[c(1,5)] 有什么作用?
  • 如果您使用facet_grid(),则无法正常工作。然后你有多个箱线图而不是一个。因此,您没有得到正确的限制。
【解决方案3】:

我遇到了同样的问题,并使用 boxplot.stats 预先计算了 Q1、Q2、中位数、ymin、ymax 的值:

# Load package and generate data
library(ggplot2)
data <- rnorm(100)

# Compute boxplot statistics
stats <- boxplot.stats(data)$stats
df <- data.frame(x="label1", ymin=stats[1], lower=stats[2], middle=stats[3], 
                 upper=stats[4], ymax=stats[5])

# Create plot
p <- ggplot(df, aes(x=x, lower=lower, upper=upper, middle=middle, ymin=ymin, 
                    ymax=ymax)) + 
    geom_boxplot(stat="identity")
p

结果是一个没有异常值的箱线图。

【讨论】:

    【解决方案4】:

    一个想法是在两遍过程中winsorize 数据:

    1. 运行第一遍,了解边界是什么,例如在给定的百分位数处截断,或高于平均值的 N 个标准差,或 ...

    2. 在第二遍中,将超出给定边界的值设置为该边界的值

    我要强调的是,这是一种老式方法,应该由更现代健壮的技术主导,但你仍然经常遇到它。

    【讨论】:

    • 谁只是默默地投了反对票:发表评论以解释为什么
    • 不是我。只是想补充一点,在环境数据中,胡须停止在百分位数(通常是第 10 位和第 90 位)似乎很常见。
    • 我是一个沉默的+1,希望我能再提供一个。 Winsorizing几乎总是在经济+金融中完成。如果 SFun 有破坏数据可视化的异常值,我想知道它们对数据分析有什么影响。
    • 在重读这篇文章时,您提到 Windsorizing 是一种较旧的技术......还有什么更现代的技术?
    • 一般来说,稳健的方法是过去 30 多年的发展。
    【解决方案5】:

    Ipaper::geom_boxplot2 正是你想要的。

    # devtools::install_github('kongdd/Ipaper')
    library(Ipaper)
    library(ggplot2)
    p <- ggplot(mpg, aes(class, hwy))
    p + geom_boxplot2(width = 0.8, width.errorbar = 0.5)
    

    【讨论】:

    • 谢谢!!用我的数据测试,工作完美!我会推荐这个解决方案,尽管我不确定 github 事物的稳定性/长期支持。
    • 嗨@Gildas,这是一个长期支持的包,这是我每天都在使用的包,github.com/rpkgs/Ipaper
    【解决方案6】:

    如果您想强制胡须扩展到最大值和最小值,您可以调整 coef 参数。 coef 的默认值为 1.5(即晶须的默认长度是 IQR 的 1.5 倍)。

    # Load package and create a dummy data frame with outliers 
    #(using example from Ramnath's answer above)
    library(ggplot2)
    df = data.frame(y = c(-100, rnorm(100), 100))
    
    # create boxplot that includes outliers
    p0 = ggplot(df, aes(y = y)) + geom_boxplot(aes(x = factor(1)))
    
    # create boxplot where whiskers extend to max and min values
    p1 = ggplot(df, aes(y = y)) + geom_boxplot(aes(x = factor(1)), coef = 500)
    

    【讨论】:

      【解决方案7】:

      简单、肮脏和有效。 geom_boxplot(outlier.alpha = 0)

      【讨论】:

      • 您好,这并没有解决 y 比例扩展过多的问题。 OP 说“我不只是希望它们消失(即 outlier.size=0),而是希望它们被忽略,以便 y 轴缩放以显示第 1/3 个百分位数。”
      【解决方案8】:

      geom_boxplot 函数的“coef”选项允许根据四分位数范围更改异常值截止值。此选项记录在函数 stat_boxplot 中。要停用异常值(换句话说,它们被视为常规数据),可以指定一个非常高的截止值,而不是使用默认值 1.5:

      library(ggplot2)
      # generate data with outliers:
      df = data.frame(x=1, y = c(-10, rnorm(100), 10)) 
      # generate plot with increased cutoff for outliers:
      ggplot(df, aes(x, y)) + geom_boxplot(coef=1e30)
      

      【讨论】:

      • 它只是扩展了胡须,它不会重新调整图表的大小
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-11-06
      • 2019-05-07
      • 1970-01-01
      • 1970-01-01
      • 2011-04-16
      • 2017-03-21
      相关资源
      最近更新 更多