在 purrr::map 中使用带有“.$”的 rsamples::bootstraps 对象时出现问题

Problem using rsamples::bootstraps object with ".$" inside purrr::map

%>% 运算符与 . 结合使用来表示 %>% 的左侧 (LHS) 对象是很常见的,例如:

library(purrr)
mtcars %>% 
  split(.$cyl) %>%    # as you can see here
  map(~ lm(mpg ~ hp, data = .x))

但是使用 rsample::bootstraps() 函数创建带有 bootstrap-list-column 的 tibble,其中每个元素都有一个数据集,我注意到使用上述 . 模式的错误我不太明白。

library(purrr)
# create a 3 partitions

# inspect how many cyl == 4 are in each partition (ERROR)
rsample::bootstraps(mtcars, times = 3) %>%
map_dbl(.$splits,
        function(x) {
                     cyl = as.data.frame(x)$cyl
                     mean(cyl == 4)
                    })
Error: Index 1 must have length 1, not 4
Run `rlang::last_error()` to see where the error occurred.

但是,如果您将 rsample::bootstraps() 的输出存储在 ex 对象中,然后使用 map_dbl,正如您在 documentation 中看到的那样,它可以正常工作.

library(purrr)
# create 3 partitions
ex <- rsample::bootstraps(mtcars, times = 3)

# inspect how many cyl == 4 are in each partition (WORKS OK)
map_dbl(ex$splits,
        function(x) {
                     cyl = as.data.frame(x)$cyl
                     mean(cyl == 4)
                    })
 [1] 0.50000 0.28125 0.43750

想了解过程之间的这种行为吗?

这个问题并不是 rsample 特有的。这就是 magrittr 中的 %>% 的工作原理。考虑

mtcars %>% 
  mean(.$carb)

这也会导致错误。因为它基本上调用的是

mean(mtcars, mtcars$carb)

默认情况下,管道总是将您要输入的内容放置到函数的第一个参数中。您可以单独使用 . 将其移动到不同的参数,但由于您没有在此处这样做,您仍然将整个第一个对象连同附加参数 [=20 一起传递给函数的第一个参数=] 但这与您要使用的 map_dbl 的签名不匹配。这适用于

mtcars %>% 
  split(.$cyl)

因为 split() 期望整个 data.frame 作为第一个参数。 split 的正确调用是

split(mtcars, mtcars$cyl)

如果您不想为您填充第一个参数,那么您可以通过管道输入一个块,而不是 {}

你可以做到

rsample::bootstraps(mtcars, times = 3) %>%
{map_dbl(.$splits,
        function(x) {
                     cyl = as.data.frame(x)$cyl
                     mean(cyl == 4)
                    })}

或者您可以 pull 显式列

rsample::bootstraps(mtcars, times = 3) %>%
  dplyr::pull(splits) %>%
  map_dbl(
        function(x) {
                     cyl = as.data.frame(x)$cyl
                     mean(cyl == 4)
                    })