在map()中,何时需要使用波浪号和句点。 (〜和。)

时间:2019-06-16 17:19:24

标签: r dplyr tidyverse purrr

我正在研究“ R For Data Science”中map()的示例。

一个例子是:

library(dplyr)
library(purrr)
df <- tibble(
  a = rnorm(10),
  b = rnorm(10),
  c = rnorm(10),
  d = rnorm(10)
)

df
#> # A tibble: 10 x 4
#>         a      b       c       d
#>     <dbl>  <dbl>   <dbl>   <dbl>
#>  1 -0.570  1.48   2.37    1.60  
#>  2  0.122  2.08   0.222   0.0338
#>  3 -0.890  0.429 -1.75   -1.48  
#>  4  0.334  0.854  0.849  -0.525 
#>  5  1.22  -0.378 -1.00   -0.147 
#>  6 -1.04  -0.427 -1.18    0.907 
#>  7 -0.392  0.102  0.0951  0.842 
#>  8  0.893  0.932  0.620  -0.911 
#>  9  1.00   0.616 -0.937  -0.0286
#> 10  0.190  1.12  -1.02    1.45

在下面的map_dbl()中,我不需要在函数map_dbl(~ mean)之前添加波浪号,也不必放置.

df %>% map_dbl(mean)

#>           a           b           c           d 
#>  0.08714704  0.68069227 -0.17382734  0.17470388

在以下示例中,我确实必须将~放在.f之前,并且还必须指定data = .

models <- mtcars %>% 
  split(.$cyl) %>% 
  map(~ lm(mpg ~ wt, data = .))
models

我已经尝试阅读以前的答案,例如What is meaning of first tilde in purrr::map,但是我仍然不确定何时需要使用波浪号和.

的确切区别。

也许对我来说,最简单的方法就是只包含这两个内容,即使它们不是绝对必要的吗?

2 个答案:

答案 0 :(得分:2)

我不是地图专家,但是这就是为什么我认为在这种情况下必须使用波浪号的原因。我认为这与应用公式而不是函数有关。

这里是一个您不必这样做的示例。在这种情况下,我要获取圆柱体列表并将其发送给函数:

cyl = mtcars%>%
  select(cyl)%>%
  unique%>%
  unlist()

model = function(CYL){

  lm(mpg ~ wt, data = mtcars%>%
       filter(cyl == !!CYL))
}

cyl%>%
  map(model)

在您的示例中,您要应用公式而不是函数。这是另一个必须使用波浪号的示例:

models <- mtcars %>% 
  split(.$cyl) %>% 
  map(~.$mpg+.$cyl)
models

在帮助图中,映射定义为:映射函数通过对每个元素应用一个函数并返回与输入长度相同的向量来转换其输入。我相信波浪号会将您的公式更改为函数。

答案 1 :(得分:1)

您的问题的快速答案是,调用map时永远不需要使用波浪号表示法。调用map的方式不同,而代字号表示法就是其中一种。您已经描述了当函数仅需要/需要一个参数时,调用map的最简单方法。

df %>% map_dbl(mean)

但是,当函数变得更加复杂时,基本上有两种方法可以使用代字号或普通的匿名函数来调用它们。

# normal anonymous function
models <- mtcars %>% 
  split(.$cyl) %>% 
  map(function(x) lm(mpg ~ wt, data = x))

# anonymous mapper function (~)
models <- mtcars %>% 
  split(.$cyl) %>% 
  map(~ lm(mpg ~ wt, data = .))

波浪号表示法基本上是将公式转换为函数,这通常更容易阅读。每个选项都可以变成一个命名函数,其功能如下。理想情况下,命名函数将基础函数的复杂度降低为一个参数(应循环调用的参数),在这种情况下,该函数可以像map中的所有简单函数一样被调用,而无需其他参数/​​符号。

# normal named function notation 
lm_mpg_wt <- function(x) {
  lm(mpg ~ wt, data = x)
}

models <- mtcars %>% 
  split(.$cyl) %>% 
  map(lm_mpg_wt)


# named mapper function
mapper_lm_mpg_wt <- as_mapper(~ lm(mpg ~ wt, data = .))

models <- mtcars %>% 
  split(.$cyl) %>% 
  map(mapper_lm_mpg_wt)

基本上,这是您的选择。您应该选择最简单,最适合您的问题的方法。如果再次需要命名函数,则它们是最好的。许多人认为,映射器功能更易于阅读,但归根结底,这是个人喜好的选择。