【问题标题】:Labeling Outliers of Boxplots in R在 R 中标记箱线图的异常值
【发布时间】:2015-11-04 14:41:58
【问题描述】:

我有创建箱线图的代码,在 R 中使用 ggplot,我想用年份和战斗标记我的异常值。

这是我创建箱线图的代码

require(ggplot2)
ggplot(seabattle, aes(x=PortugesOutcome,y=RatioPort2Dutch ),xlim="OutCome", 
y="Ratio of Portuguese to Dutch/British ships") + 
geom_boxplot(outlier.size=2,outlier.colour="green") + 
stat_summary(fun.y="mean", geom = "point", shape=23, size =3, fill="pink") + 
ggtitle("Portugese Sea Battles")

有人可以帮忙吗?我知道这是正确的,我只想标记异常值。

【问题讨论】:

  • 数据seabattle从哪里来?您能否dput 数据或提供示例数据以使此示例可重现?
  • 你已经尝试过什么了吗?

标签: r ggplot2 boxplot direct-labels


【解决方案1】:

以下是使用dplyr 和内置mtcars 数据集的可重现解决方案。

浏览代码:首先,创建一个函数is_outlier,如果传递给它的值是异常值,它将返回一个布尔值TRUE/FALSE。然后我们执行“分析/检查”并绘制数据——首先我们group_by我们的变量(在这个例子中是cyl,在你的例子中,这将是PortugesOutcome)我们添加一个变量outliermutate 的调用(如果drat 变量是异常值[注意这对应于您的示例中的RatioPort2Dutch],我们将传递drat 值,否则我们将返回NA,因此该值不是绘制)。最后,我们通过geom_text 绘制结果并绘制文本值,以及与我们的新变量相等的美学标签;此外,我们使用hjust 偏移文本(将其向右滑动一点),以便我们可以看到离群点旁边而不是顶部的值。

library(dplyr)
library(ggplot2)

is_outlier <- function(x) {
  return(x < quantile(x, 0.25) - 1.5 * IQR(x) | x > quantile(x, 0.75) + 1.5 * IQR(x))
}

mtcars %>%
  group_by(cyl) %>%
  mutate(outlier = ifelse(is_outlier(drat), drat, as.numeric(NA))) %>%
  ggplot(., aes(x = factor(cyl), y = drat)) +
    geom_boxplot() +
    geom_text(aes(label = outlier), na.rm = TRUE, hjust = -0.3)

【讨论】:

    【解决方案2】:

    您可以简单地在 ggplot 内部执行此操作,使用适当的 stat_summary 调用。

    ggplot(mtcars, aes(x = factor(cyl), y = drat, fill = factor(cyl))) + 
      geom_boxplot() +
      stat_summary(
        aes(label = round(stat(y), 1)),
        geom = "text", 
        fun.y = function(y) { o <- boxplot.stats(y)$out; if(length(o) == 0) NA else o },
        hjust = -1
      )
    

    【讨论】:

    • 如何修改 aes 调用以使用其他变量(例如 mpg)标记异常值?我曾尝试在 stat_summary 和顶部 ggplot 调用中调用 aes(label = mpg),但我收到错误消息,说 geom_text 需要缺少标签美学。
    【解决方案3】:

    用行名标记异常值(基于JasonAizkalns 答案)

    library(dplyr)
    library(ggplot2)
    library(tibble)
    
    is_outlier <- function(x) {
      return(x < quantile(x, 0.25) - 1.5 * IQR(x) | x > quantile(x, 0.75) + 1.5 * IQR(x))
    }
    
    dat <- mtcars %>% tibble::rownames_to_column(var="outlier") %>% group_by(cyl) %>% mutate(is_outlier=ifelse(is_outlier(drat), drat, as.numeric(NA)))
    dat$outlier[which(is.na(dat$is_outlier))] <- as.numeric(NA)
    
    ggplot(dat, aes(y=drat, x=factor(cyl))) + geom_boxplot() + geom_text(aes(label=outlier),na.rm=TRUE,nudge_y=0.05)
    

    【讨论】:

      【解决方案4】:

      这对你有用吗?

      library(ggplot2)
      library(data.table)
      
      #generate some data
      set.seed(123)
      n=500
      dat <- data.table(group=c("A","B"),value=rnorm(n))
      

      ggplot 默认将异常值定义为距离框的边界 > 1.5*IQR。

      #function that takes in vector of data and a coefficient,
      #returns boolean vector if a certain point is an outlier or not
      check_outlier <- function(v, coef=1.5){
        quantiles <- quantile(v,probs=c(0.25,0.75))
        IQR <- quantiles[2]-quantiles[1]
        res <- v < (quantiles[1]-coef*IQR)|v > (quantiles[2]+coef*IQR)
        return(res)
      }
      
      #apply this to our data
      dat[,outlier:=check_outlier(value),by=group]
      dat[,label:=ifelse(outlier,"label","")]
      
      #plot
      ggplot(dat,aes(x=group,y=value))+geom_boxplot()+geom_text(aes(label=label),hjust=-0.3)
      

      【讨论】:

        【解决方案5】:

        与上述类似的答案,但直接从ggplot2 获取异常值,从而避免方法中的任何潜在冲突:

        # calculate boxplot object
        g <- ggplot(mtcars, aes(factor(cyl), drat)) + geom_boxplot()
        
        # get list of outliers 
        out <- ggplot_build(g)[["data"]][[1]][["outliers"]]
        
        # label list elements with factor levels
        names(out) <- levels(factor(mtcars$cyl))
        
        # convert to tidy data
        tidyout <- purrr::map_df(out, tibble::as_tibble, .id = "cyl")
        
        # plot boxplots with labels
        g + geom_text(data = tidyout, aes(cyl, value, label = value), 
                      hjust = -.3)
        

        【讨论】:

          【解决方案6】:

          对@JasonAizkalns 解决方案稍作改动,您可以使用异常值在数据框中的位置来标记它们。

          mtcars[,'row'] <- row(mtcars)[,1]
          ...
          mutate(outlier = ifelse(is_outlier(drat), row, as.numeric(NA)))
          ...
          

          我将数据框加载到 R Studio 环境中,因此我可以仔细查看异常行中的数据。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2013-02-17
            • 2021-11-06
            • 2020-08-27
            • 1970-01-01
            • 2013-07-17
            • 1970-01-01
            • 2021-01-14
            • 1970-01-01
            相关资源
            最近更新 更多