分组时覆盖箱线图中的下限、上限等

2024-01-02

默认情况下,对于下、中和上分位数geom_boxplot考虑 25%、50% 和 75% 分位数。这些是从计算得出的y,但可以通过美学参数手动设置lower, upper, middle(还提供x, ymin and ymax和设置stat="identity").

然而,这样做会产生一些不良影响(参见示例代码中的版本 1):

  • 论据group被忽略,因此计算中会考虑列的所有值(例如,计算每个组的最低分位数时)
  • 生成的相同箱线图按以下分组:x,并在数据中出现特定组值时在组内重复(而不是将框合并到更宽的框)
  • 未绘制异常值

通过预先计算所需值并将其存储在新的数据框中,可以处理前两点(参见示例代码中的版本 2),而第三点则通过识别异常值并将它们单独添加到数据框中来修复。图表通过geom_point.

是否有更直接的方法来更改分位数,而不会产生这些不良影响?

示例代码:

set.seed(12)

# Random data in B, grouped by values 1 to 4 in A
u <- data.frame(A = sample.int(4, 100, replace = TRUE), B = rnorm(100))

# Desired arguments
qymax <- 0.9
qymin <- 0.1
qmiddle <- 0.5
qupper <- 0.8
qlower <- 0.2

版本 1:A 中每个值的重复箱线图,按 A 分组

ggplot(u, aes(x = A, y = B)) + 
  geom_boxplot(aes(group=A, 
                   lower = quantile(B, qlower), 
                   upper = quantile(B, qupper), 
                   middle = quantile(B, qmiddle), 
                   ymin = quantile(B, qymin), 
                   ymax = quantile(B, qymax) ), 
               stat="identity")

版本 2:首先计算每个组的参数。基础R溶液

Bgrouped <- lapply(unique(u$A), function(a) u$B[u$A == a])
.lower <- sapply(Bgrouped, function(x) quantile(x, qlower))
.upper <- sapply(Bgrouped, function(x) quantile(x, qupper))
.middle <- sapply(Bgrouped, function(x) quantile(x, qmiddle))
.ymin <- sapply(Bgrouped, function(x) quantile(x, qymin))
.ymax <- sapply(Bgrouped, function(x) quantile(x, qymax))

u <- data.frame(A = unique(u$A), 
                lower = .lower, 
                upper = .upper, 
                middle = .middle, 
                ymin = .ymin, 
                ymax = .ymax)    

ggplot(u, aes(x = A)) + 
  geom_boxplot(aes(lower = lower, upper = upper, 
                   middle = middle, ymin = ymin, ymax = ymax ), 
               stat="identity")

如果没有的话我真的不会做这件事lot合理性,因为人们通常期望箱线图的最小/最大/箱值对应于相同的分位数位置,但这是可以做到的。

使用的数据(添加极值以显示异常值):

set.seed(12)
u <- data.frame(A = sample.int(4, 100, replace = TRUE), B = rnorm(100))
u$B[c(30, 70, 76)] <- c(4, -4, -5)

解决方案1:您可以预先计算值,而无需通过基本 R 路线,并在同一步骤中包括异常值的计算。我会完全在 Hadley 的 tidyverse 库中完成它,我发现它更整洁:

library(dplyr)
library(tidyr)

u %>%
  group_by(A) %>%
  summarise(lower = quantile(B, qlower),
            upper = quantile(B, qupper), 
            middle = quantile(B, qmiddle), 
            IQR = diff(c(lower, upper)),
            ymin = max(quantile(B, qymin), lower - 1.5 * IQR), 
            ymax = min(quantile(B, qymax), upper + 1.5 * IQR),
            outliers = list(B[which(B > upper + 1.5 * IQR | 
                                      B < lower - 1.5 * IQR)])) %>%
  ungroup() %>% 
  ggplot(aes(x = A)) + 
  geom_boxplot(aes(lower = lower, upper = upper,
                   middle = middle, ymin = ymin, ymax = ymax ),
               stat="identity") + 
  geom_point(data = . %>% 
               filter(sapply(outliers, length) > 0) %>%
               select(A, outliers) %>%
               unnest(), 
             aes(y = unlist(outliers)))

解决方案2:您可以覆盖 ggplot 使用的实际分位数规范。计算为geom_boxplot()的分位数实际上是在StatBoxplot's compute_group()函数,发现here https://github.com/cran/ggplot2/blob/master/R/stat-boxplot.r:

compute_group = function(data, scales, width = NULL, na.rm = FALSE, coef = 1.5) {
    qs <- c(0, 0.25, 0.5, 0.75, 1)

    if (!is.null(data$weight)) {
      mod <- quantreg::rq(y ~ 1, weights = weight, data = data, tau = qs)
      stats <- as.numeric(stats::coef(mod))
    } else {
      stats <- as.numeric(stats::quantile(data$y, qs))
    }

... (omitted for space)

The qs矢量定义分位数位置。它不受传递给的参数的影响compute_group(),所以改变它的唯一方法是改变定义compute_group() itself:

# save a copy of the original function, in case you need to revert
original.function <- environment(ggplot2::StatBoxplot$compute_group)$f

# define new function (only the first line for qs is changed, but you'll have to
# copy & paste the whole thing)
new.function <- function (data, scales, width = NULL, na.rm = FALSE, coef = 1.5) {
  qs <- c(0.1, 0.2, 0.5, 0.8, 0.9)
  if (!is.null(data$weight)) {
    mod <- quantreg::rq(y ~ 1, weights = weight, data = data, 
                        tau = qs)
    stats <- as.numeric(stats::coef(mod))
  }
  else {
    stats <- as.numeric(stats::quantile(data$y, qs))
  }
  names(stats) <- c("ymin", "lower", "middle", "upper", "ymax")
  iqr <- diff(stats[c(2, 4)])
  outliers <- data$y < (stats[2] - coef * iqr) | data$y > (stats[4] + 
                                                             coef * iqr)
  if (any(outliers)) {
    stats[c(1, 5)] <- range(c(stats[2:4], data$y[!outliers]), 
                            na.rm = TRUE)
  }
  if (length(unique(data$x)) > 1) 
    width <- diff(range(data$x)) * 0.9
  df <- as.data.frame(as.list(stats))
  df$outliers <- list(data$y[outliers])
  if (is.null(data$weight)) {
    n <- sum(!is.na(data$y))
  }
  else {
    n <- sum(data$weight[!is.na(data$y) & !is.na(data$weight)])
  }
  df$notchupper <- df$middle + 1.58 * iqr/sqrt(n)
  df$notchlower <- df$middle - 1.58 * iqr/sqrt(n)
  df$x <- if (is.factor(data$x)) 
    data$x[1]
  else mean(range(data$x))
  df$width <- width
  df$relvarwidth <- sqrt(n)
  df
}

Result:

# toggle between the two definitions
environment(StatBoxplot$compute_group)$f <- original.function
ggplot(u, aes(x = A, y = B, group = A)) +
  geom_boxplot() +
  ggtitle("original definition for calculated quantiles")

environment(StatBoxplot$compute_group)$f <- new.function
ggplot(u, aes(x = A, y = B, group = A)) +
  geom_boxplot() +
  ggtitle("new definition for calculated quantiles")

请注意,当您更改定义时,它会影响环境中的每个 ggplot 对象。因此,如果您创建了 ggplot boxplot 对象before定义更改,并将其打印出来然后,箱线图将遵循新的定义。 (对于上面的并排比较,我必须立即将每个 ggplot 转换为 grob 对象,以保留差异。)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

分组时覆盖箱线图中的下限、上限等 的相关文章

随机推荐

  • Akka 适合短暂网络覆盖的系统吗?

    Akka 是否适合在节点需要进出 WiFi 覆盖范围的系统中使用 必须考虑哪些方面 例如首选哪些传输协议 Akka is适用于具有瞬态网络覆盖的系统 正如 Viktor 在对该问题的评论中指出的那样 主管层次结构可用于处理未交付错误 有关更
  • H2DB 中如何像 MySql 中那样获取 sql 转储?

    我有 H2DB 数据库 它将数据存储在文件中 我有3个文件 test 18 log db test data db and test index db 我想要像我使用时一样获取 SQL 转储文件mysqldump 是否可以 是的 有多种解决
  • 喷气背包上的调整大小组合不起作用

    我正在使用 jetpack compose 1 0 0 beta09 在我的项目上实现一个屏幕 但我在屏幕上遇到了一个问题 即使键盘打开 页脚也需要始终可见 我知道我们有android 上的 adjustResize 在正常活动中解决了这个
  • C++ 中无符号整数提升

    int main unsigned i 5 int j 10 double d i j long l i j int k i j std cout lt lt d lt lt n 4 29497e 09 std cout lt lt l l
  • jquery - $.functionName 和 $.fn.FunctionName 之间的区别

    在 jQuery 中 我见过以下两种定义 jQuery 函数的方法 fn CustomAlert function alert boo CustomAlert function alert boo 我知道它们附加到 jQuery 对象 或
  • sql联合顺序

    我有一张桌子 上面有学生的姓名和身高 我想要一个查询 按字母顺序对身高高于 150 厘米的学生进行排序 对身高低于 150 厘米的学生按姓名降序排列 像这样的东西 select from students where height gt 1
  • Visual Studio:是否对整个解决方案进行增量搜索?

    我非常喜欢 Visual Studio 中内置的键盘快捷键 我最喜欢的之一是Ctrl i 这会触发增量搜索 当我填写搜索词时 它会跳过当前文档中的文本 输入所需的搜索词后 我使用F3跳过比赛 它工作正常 除了仅限于搜索当前文件 此外 触发增
  • 我是否应该将“贷款”、“采购”和“销售”表非规范化为一张表?

    根据我在下面提供的信息 您能否就将单独的表非规范化为一个包含不同类型合约的表是否是个好主意发表意见 优点 缺点是什么 有没有人尝试过这样做之前 银行系统使用 CIF 客户信息文件 主 客户可能拥有不同类型的账户 CD 抵押贷款等 并使用交易
  • 向 Swift 2 中的类添加“for...in”支持

    这个问题 https stackoverflow com questions 24099227 add for in support to iterate over swift custom classes早期版本的 Swift 已经得到了
  • 如何在 Swift 中发出 NSURLSession POST 请求

    你好 我是 Swift 的初学者 我正在尝试让 NSURLSession Post 请求发送一些参数 如下面的代码 根据我的下面的代码响应不是来自服务器 有人可以帮助我吗 背景类别 import UIKit protocol sampleP
  • 致命的 Python 错误:无法从堆栈溢出中恢复

    我在互联网上读到类似的问题 但没有一个答案可以帮助我 我有一个函数 对于每一行数据 数据大约有 2 000 000 行 执行一些操作 然后根据它所做的操作使用不同的参数调用相同的函数 问题是 过了一会儿 我在终端中收到此错误 致命的 Pyt
  • nvd3 工具提示十进制格式

    我正在使用 nvd3 显示折线图 格式化工具提示内容时遇到一些问题 这是我用来设置 y 轴文本格式的行 chart1 yAxis tickFormat d3 format 02f 但是 它仅对 y 轴有效 如果有一个像 44 123231
  • android startActivity 来自服务中的意图[重复]

    这个问题在这里已经有答案了 我尝试在服务中使用意图 但是当我尝试这样做时 Intent intent facebook new Intent this MainUploadToYoutube class intent facebook pu
  • Instagram新API,通过标签获取项目

    上个月 Instagram API 更新了 我不明白如何使用它 例如我想通过标签获取图像nexus5x 我确实请求https api instagram com v1 tags nexus5x access token access tok
  • 将背景图像 (SVG) 拉伸至 100% 宽度和 100% 高度?

    我想要实现的行为是宽度background size cover 但高度为background size contain 通过拉伸图像 我以为background size 100 应该这样做 但看看这个例子 它没有 container b
  • 使用 include 动态指向 HTML

    我想基于变量指向不同的 HTML 文件 我使用以下格式的 include include templates case cid intro html 这会引发错误 TemplateNotFound templates case cid in
  • Oracle ojdbc8 12.2.0.1 被 Maven 禁止

    Oracle ojdbc8 12 2 0 1禁止自 2017 年 12 月起由 Maven 提供 在此之前效果良好 Oracle 存储库 setting xml 上的哪些配置已更改 Maven 项目 https github com sgr
  • 使用不同的 JSON 对象填充 ViewPager 中的每个片段,而无需再次加载

    我有一个ViewPager有一个Fragment其中包含一个 GridView仅当我延迟滚动页面并且每次再次从互联网检索内容时 我的代码才能正常工作我想做的只是获取每个页面内容一次并在用户滚动页面时使用它我的问题之一是 JSON 下载sim
  • swift中的dispatch_group_leave崩溃

    这种情况很少发生 这是堆栈跟踪的最后一行 0 libdispatch dylib 0x0000000197a85a9c dispatch group leave 48 dispatch group leave 在一个完整的闭包中被调用 调用
  • 分组时覆盖箱线图中的下限、上限等

    默认情况下 对于下 中和上分位数geom boxplot考虑 25 50 和 75 分位数 这些是从计算得出的y 但可以通过美学参数手动设置lower upper middle 还提供x ymin and ymax和设置stat ident