如何使用 magrittr 三通管道 %T>% 为 R 中的分组数据创建多个 ggplots

How to use magrittr Tee pipe %T>% to create multiple ggplots for grouped data in R

提问人:dez93_2000 提问时间:6/10/2023 最后编辑:dez93_2000 更新时间:6/13/2023 访问量:96

问:

我正在尝试为每个组创建直方图,然后返回摘要。根据这个答案,我可以使用{大括号},以避免在创建一个图然后移动到另一个图时出现问题,但是这似乎不承认分组:print

data(mtcars)
mtcars |> 
  group_by(cyl) %T>%
  {print(ggplot(.) +
           geom_histogram(aes(x = carb)))} |> 
  summarise(meancarb = mean(carb))

上面的代码在创建单个直方图和摘要时有效,但是:

mtcars %T>%
  {print(ggplot(.) +
           geom_histogram(aes(x = carb)))} |> 
  group_by(cyl) |> 
  summarise(meancarb = mean(carb))

上面的代码产生完全相同的输出,即确认未被确认。group_by

有谁知道为什么不使用分组为每个唯一创建 1 个直方图?理想情况下,我很想弄清楚如何使用 T 形管道更频繁地做这种事情,包括将输出保存为唯一名称,然后再继续使用更多管道。总的来说,感觉 Tee 管道未得到充分利用,可能与缺乏有关它们的信息有关,所以如果有人有任何很酷的例子可以分享,这对社区来说可能是件好事。cyl

谢谢!

编辑

以下 divibisan 对(或)的评论:dplyr::group_mapgroup_walk

mtcars |> 
  group_by(cyl) %T>%
  group_walk(.f = ~ ggplot(.) +
              geom_histogram(aes(x = carb))) |> 
  summarise(meancarb = mean(carb, na.rm = TRUE),
            sd3 = sd(carb, na.rm = TRUE) * 3)

这将创建汇总表,但不会创建绘图。输出与 相同。如果我用 替换 ,输出也相同。表面上,它正在做与 .有了 和 ,我得到:mapwalk%T>%|>group_walk%T>%|>group_map

UseMethod(“summarise”) 中的错误:没有适用的“summarise”方法 应用于类“list”的对象

mtcars |> 
  group_by(cyl) %T>%
  {print(group_walk(.f = ~ ggplot(.) +
              geom_histogram(aes(x = carb))))} |> 
  summarise(meancarb = mean(carb, na.rm = TRUE),
            sd3 = sd(carb, na.rm = TRUE) * 3)

带印花和大括号:

h(simpleError(msg, call)) 中的错误:计算参数时出错 为函数“print”选择方法时的“x”:参数“.data”是 missing,无默认值

大括号无打印:

group_map(.data, .f, ..., .keep = .keep) 中的错误:参数“.data”是 missing,无默认值

不打印大括号:与大括号不打印相同。

编辑2

多亏了里卡多,更多有趣的想法出现了:

mtcars |> 
  group_split(cyl) |> 
  map(.f = ~ ggplot(.) +
        geom_histogram(aes(x = carb)))

只要它每组产生 1 个图,就可以工作。成功!但是:我找不到任何 Tee/管道的组合,这些组合为 AND 开球,然后恢复主管道:mtcarsgroup_splitmap

mtcars %T>% 
  group_split(cyl) %T>%
  map(.f = ~ ggplot(.) +
               geom_histogram(aes(x = carb))) |>
  summarise(meancarb = mean(carb))

错误:在索引中: 1.名称:mpg。由 中的错误引起 : 必须是 <data.frame>,或者是可由 强制的对象,而不是双精度向量。map()fortify()datafortify()

此外,除 2 个管道以外的任何内容都意味着不会创建绘图。

通过重新排序管道结构(这并不总是可行/可取的)来尝试另一种方式:

mtcars |>
  group_by(cyl) %T>%
  summarise(meancarb = mean(carb)) |> 
  ungroup() |> 
  group_split(cyl) |> 
  map(.f = ~ ggplot(.) +
        geom_histogram(aes(x = carb)))

这将创建 3 个图,但不打印摘要。{大括号}和/或摘要行周围的任何组合都给出:print

h 中的错误(simpleError(msg, call)): 计算参数时出错 为函数“mean”选择方法时出现“x”:找不到对象“carb”。

有谁知道 Tee 管道是否明确用于单个命令,即您不能将另一个命令管道传输到 T 形分支,然后返回到主管道?谢谢大家

编辑 3

谢谢zephyr。后续问题:如何在没有公式格式第一个命令的情况下进行多命令三通管?

mtcars |>
  summarise(sdd = sd(carb, na.rm = TRUE))

工作正常,打印单个值。

mtcars %T>%
  summarise(sdd = sd(carb, na.rm = TRUE)) |> 
  summarise(
    meancarb = mean(carb, na.rm = TRUE),
    sd3 = sd(carb, na.rm = TRUE) * 3
  )

不打印值,以不可见的方式执行计算,然后继续。和我尝试过的任意组合都会导致:print{braces}

错误:管道的 RHS 调用不支持函数“{”

is.data.frame(x) 中的错误:找不到对象“carb”

说我想要,例如:

mtcars  |> 
  summarise(~{
    print(sdd = sd(carb))
    write_csv(file = "tmp.csv")
    .x
  }) |> 
  summarise(meancarb = mean(carb))

有什么想法吗?再次感谢!

R GGPLOT2 按管道 magrigtr 分组

评论

1赞 divibisan 6/10/2023
也许我遗漏了一些东西,但我不认为 ggplot 在传递分组数据框时会绘制多个图。我认为你需要在大括号内放一个group_map来制作多个图,或者通过以下方式对图进行刻面cyl
0赞 dez93_2000 6/10/2023
谢谢你的信息,这些对我来说是新的。在尝试了几个变体后更新了问题。可以回退到facet_plot但很高兴看到我们是否可以做到这一点。
1赞 Ricardo Semião e Castro 6/10/2023
也许进入而不是group_splitmapgroup_by

答:

2赞 zephryl 6/10/2023 #1

你走在正确的轨道上,但你需要把映射的函数放在里面:group_walk()print()

library(dplyr)
library(purrr)
library(magrittr)
library(ggplot2)

mtcars |> 
  group_by(cyl) %T>%
  group_walk(~ print(
    ggplot(.) + geom_histogram(aes(x = carb))
  )) |> 
  summarise(
    meancarb = mean(carb, na.rm = TRUE),
    sd3 = sd(carb, na.rm = TRUE) * 3
  )
# A tibble: 3 × 3
    cyl meancarb   sd3
  <dbl>    <dbl> <dbl>
1     4     1.55  1.57
2     6     3.43  5.44
3     8     3.5   4.

请注意,您可以通过在匿名函数中将绘图分配给名称并在打印后返回原始数据帧来获得相同的结果:%T>%

mtcars |> 
  group_by(cyl) |>
  group_walk(~ {
    p <- ggplot(.x) + geom_histogram(aes(x = carb))
    print(p)
    .x
  }) |> 
  summarise(
    meancarb = mean(carb, na.rm = TRUE),
    sd3 = sd(carb, na.rm = TRUE) * 3
  )

评论

1赞 zephryl 6/13/2023
例如,对于 1,几乎是肯定的——不起作用的原因是没有返回任何内容,所以没有什么可打印的。您也可以这样做,这将打印 返回的绘图列表。例如,支撑的目的是包含一个多行函数作为 的参数。print(group_walk())group_walk(){print(group_map(., ~ ggplot(.x) + geom_histogram(aes(x = carb))))}group_map()group_walk()
1赞 zephryl 6/13/2023
回复“任何分配然后打印 p 与打印(ggplot ...碳水化合物)))?不,你是对的 -- 关键是打印绘图然后返回,但你不必在打印前分配绘图。.x
1赞 zephryl 6/13/2023
对于最后一个问题,在更简单的情况下可能很有用 - 例如,如果您想在管道中的不同步骤保存数据帧的版本,您可以执行 .但在实践中,我很少发现它有用。%T>%dat %T%> write.csv("all_data.csv") %>% summarize(mean_x = mean(x)) ...
1赞 zephryl 6/13/2023
你可以做,把你想“跳过”的所有东西都放在大括号里。不过,这绝对不是惯用的——在大多数情况下,我只会制作两个单独的管道。mtcars %T>% { summarise(., sdd = sd(carb)) |> print() |> write_csv("tmp.sav") } |> summarise(meancarb = mean(carb))
1赞 zephryl 6/13/2023
是的 - 但用大括号括起来会覆盖这一点。请参阅文档,尤其是本节本节%>%