【问题标题】:Piping histograms in dplyr (R)dplyr (R) 中的管道直方图
【发布时间】:2016-07-25 21:45:54
【问题描述】:

是否可以在 dplyr.

这是有效的:

birdsss = data.frame(x1 = 1:10,x2 = 21:30,x3 = 41:50)
birdsss%>%  
  with(hist(x1, breaks = 50))

但这不起作用:

birdsss%>%  
  with(hist(x1, breaks = 50)) %>%  
  with(hist(x2, breaks = 50)) %>%  
  with(hist(x3, breaks = 50))
Error in hist(x2, breaks = 50) : object 'x2' not found

我也试过了:

birdsss%>%  
  with(hist(x1, breaks = 50)) &  
  with(hist(x2, breaks = 50)) &  
  with(hist(x3, breaks = 50))

birdsss%>%  
  with(hist(x1, breaks = 50)) ;  
  with(hist(x2, breaks = 50)) ; 
  with(hist(x3, breaks = 50))

在一行中打印多列的解决方案是什么?

类似:

 birdsss%>%  
      with(hist(x1:x3, breaks = 50))

我正在使用更长的管道(filter()、select() 等)以及如何使用多个图形来完成。我在这里简化了代码。

【问题讨论】:

  • 我喜欢 dplyr,但lapply(birdsss, hist, breaks = 50) 更容易。如果你真的想要一个 tidyverse 版本,请使用 purrrmapwalk
  • 问题是我受到我正在使用的代码的限制,因为我也在使用 filter()、select() 等。这就是为什么我认为在管道内使用 apply...但它也不起作用。
  • 这真的不是一个或另一个; base 和 tidyverse 完美地结合在一起。如果您愿意,可以链接到 lapply,例如birdsss %>% lapply(hist, breaks = 50)。如果你要完整的 tidyverse,请使用 ggplot2 并且只是方面:birdsss %>% tidyr::gather() %>% ggplot(aes(value)) + geom_histogram(bins = 51) + facet_wrap(~key)
  • 酷!我没有以正确的方式“应用”!是否可以更改 lapply 函数内的图形标题。我试过 main = c("something1","something2","something3"),但它不起作用
  • 由于您现在尝试并行传递两个参数,因此您可以将 mapply/Map 用于多变量版本(或各种 purrr 版本,例如 map2/@987654337 @,哪个更容易链接)。在这里,可能是Map(function(x, y){hist(x, breaks = 50, main = y)}, birdsss, names(birdsss)),或者purrr 版本:walk2(birdsss, names(birdsss), ~hist(.x, breaks = 50, main = .y))

标签: r dplyr histogram


【解决方案1】:

lapply

要将我上面的一些 cmets 放入答案中,制作每个变量的直方图的最简单方法是

# let's put them in a single plot
par(mfrow = c(1, 3))

lapply(birdsss, hist, breaks = 50)    # or chain into it: birdsss %>% lapply(hist, breaks = 50)

# set back to normal
par(mfrow = c(1, 1))

不过,这确实弄乱了标签:

Map/mapply

要使用 base 解决此问题,我们需要并行迭代数据和标签,这可以通过 Mapmapply 完成(因为我们不关心结果——只关心副作用——区别无关紧要):

par(mfrow = c(1, 3))

Map(function(x, y){hist(x, breaks = 50, main = y, xlab = y)}, 
    birdsss, 
    names(birdsss))

par(mfrow = c(1, 1))

漂亮多了。但是,如果你想链接到它,你需要使用. 来显示数据应该去哪里:

birdsss %>% 
    Map(function(x, y){hist(x, breaks = 50, main = y, xlab = y)}, 
        ., 
        names(.))

咕噜声

Hadley 的purrr 包使*apply 风格的循环更明显可链接(虽然不相关,但使用列表更容易),而无需担心.s。在这里,由于您正在迭代副作用并且想要迭代两个变量,请使用walk2

library(purrr)

walk2(birdsss, names(birdsss), ~hist(.x, breaks = 50, main = .y, xlab = .y))

它返回与之前的Map 调用完全相同的内容(如果您以相同的方式设置mfrow),但不会向控制台输出无用的输出。 (如果您需要该信息,请改用map2。)请注意,要迭代的参数排在第一位,因此您可以轻松链接:

birdsss %>% walk2(names(.), ~hist(.x, breaks = 50, main = .y, xlab = .y))

ggplot

采用完全不同的策略,如果您最终还是打算将所有内容都放在一个情节中,那么 ggplot2 使用其facet_* 函数可以非常轻松地制作相关情节:

library(ggplot2)

# gather to long form, so there is a variable of variables to split facets by
birdsss %>% 
    tidyr::gather(variable, value) %>% 
    ggplot(aes(value)) + 
        # it sets bins intead of breaks, so add 1
        geom_histogram(bins = 51) + 
        # make a new "facet" for each value of `variable` (formerly column names), and 
        # use a convenient x-scale instead of the same for all 3
        facet_wrap(~variable, scales = 'free_x')

它看起来有点不同,但一切都是可编辑的。请注意,您无需任何工作即可获得漂亮的标签。

【讨论】:

    【解决方案2】:

    普通管道%>% 将左侧管道传输到右侧。 hist 返回一个(非常有用的)hist 对象,但它不是您可以通过管道传输到另一个直方图的数据。你想要“T”管道:

    library(magrittr)
    birdsss %T>%  
      with(hist(x1, breaks = 50)) %T>%  
      with(hist(x2, breaks = 50)) %T>%  
      with(hist(x3, breaks = 50))
    

    这会将第一个“T”之前的内容传递给之后的内容。详情请见the magrittr documentation

    【讨论】:

    • 哇,从未听说过 T 管!这可能会改变生活。
    • 我的意思是,我发现普通烟斗在某种程度上改变了生活,但 T 烟斗只是一种新奇事物。如果您真的想要在链条中间有一个中间情节,它可能很有用,但我通常认为这会损害可读性 - 我宁愿打破链条,制作情节,然后继续。跨度>
    • 也就是说,如果你喜欢这种事情,我想你会发现分配管道%<>% 比 T 管道更有用。
    【解决方案3】:

    另一种方法:

    library(dplyr)
    library(tidyr)
    
    birdsss <- data.frame(x1 = 1:10, x2 = 21:30, x3 = 41:50)
    
    my_hist <- function(x) { 
      hist(x$val, breaks=50, xlab=x$var[1], main=sprintf("Histogram of %s", x$var[1]))
    }
    
    par(mfrow=c(3,1))
    birdsss %>% 
      gather(var, val, x1, x2, x3) %>% 
      group_by(var) %>% 
      do(a=my_hist(.)) %>% 
      invisible()
    par(mfrow=c(1,1))
    

    【讨论】:

    • 我注意到如果使用geom_histogram() 会更“干净”,但我尽量不要强加给那些在基本图形中给出主要示例的人。
    【解决方案4】:

    你可以试试:

    attach(birdsss)
    
    hist(x1,breaks = 50)
    hist(x2,breaks = 50)
    hist(x3,breaks = 50)
    
    detach(birdsss)
    

    或者可能更好:

    with(birdsss,{
            hist(x1,breaks = 50)
            hist(x2,breaks = 50)
            hist(x3,breaks = 50)
         }
    
         )
    

    我记得在某处读到使用attach 会导致混淆。

    【讨论】:

    • attach 是一种肮脏的习惯,应该劝阻。
    • @Gregor,是的,正如我提到的,我记得读过它,但我从未完全理解attach 的危险。你能推荐一个能清楚解释这一点的来源吗?
    • 我不知道一个好的来源,但我的附加问题是 1)如果您的全局环境中已经有与列名同名的对象,它可能会导致错误 2)如果附加后,您做任何复杂的事情都很容易使列不同步(一列重新排列,或丢失几行等) 3)您附加的列与数据框不同步。总体而言,我认为便利性很小(with 也可以正常工作,而采用data 参数的函数也不需要),但潜在的问题很大。
    【解决方案5】:

    如果您想将其完全保留在 dplyr 中,您可以简单地使用 select 函数来选择您希望生成直方图的变量,以便使用以下解决方案:

    hist((birdsss %>%  
      select(x1:x3)), breaks = 20)
    

    【讨论】:

      猜你喜欢
      • 2020-11-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-27
      • 2019-11-18
      • 1970-01-01
      • 2013-06-17
      相关资源
      最近更新 更多