在purrr中使用dplyr :: if_else

时间:2019-06-20 17:17:26

标签: r

如果列表元素为purrr::map_dbl,我想在想要不同行为的列表上使用NULL

x <- list(NULL, c(1, 2), c(3, 4))
purrr::map_dbl(x, function(y) { dplyr::if_else(is.null(y), 0, y[1] + y[2]) })

这无法正常工作,而是出现错误:

  

错误:false的长度必须为1(condition的长度),而不是0

调试if_else调用后,我发现y[1] + y[2]被评估为integer(0)。为什么这行不通?

以下所有工作均符合我的预期:

> purrr::map_dbl(x, function(y) { dplyr::if_else(is.null(y), 0, y[1]) })
[1] 0 1 3
> purrr::map_dbl(x, function(y) { dplyr::if_else(is.null(y), 0, y[2]) })
[1] 0 2 4
> purrr::map_dbl(x, ~ dplyr::if_else(is.null(.x), 0, .x[1]))
[1] 0 1 3
> purrr::map_dbl(x, function(y) { base::ifelse(is.null(y), 0, y[1] + y[2]) })
[1] 0 3 7
> purrr::map_dbl(x, function(y) { if (is.null(y)) 0 else y[1] + y[2] })
[1] 0 3 7

原始通话有何不同?

2 个答案:

答案 0 :(得分:2)

一种替代方法是在将值加在一起时,使用na.rm中的sum参数忽略NANULL值。这样,我们可以跳过if else逻辑:

purrr::map_dbl(x, sum, na.rm = TRUE) 
# [1] 0 3 7

这是Base R的等效项(如akrun所指出):

sapply(x, sum, na.rm = TRUE)

答案 1 :(得分:1)

我们可以使用browser()进行调试,

purrr::map_dbl(x, function(y) {
        browser()
        dplyr::if_else(is.null(y), 0, y[1] + y[2]) 
 })
Called from: .f(.x[[i]], ...)
Browse[1]> 
debug at #1: dplyr::if_else(is.null(y), 0, y[1] + y[2])
Browse[2]> 
Error: `false` must be length 1 (length of `condition`), not 0
Call `rlang::last_error()` to see a backtrace

因此,这里的length是问题所在。

根据?if_else,要求所有参数的长度都相同

  

用于条件的TRUE和FALSE值的值。它们的长度必须与条件相同,或者长度为1。它们还必须具有相同的类型:if_else()检查它们是否具有相同的类型和相同的类。所有其他属性均取自true。


要进一步研究问题,如果值不是NULL

,它仍然有效
v1 <- 1
if_else(v1==1, 0, v1[1] + v1[2])
#[1] 0

但是,一旦我们将其更改为NANULL,就会成为问题,可能是由于type

@CBraun进行了有趣的观察

NULL[1] + NULL[2]
#integer(0)

返回长度0,

if_else(is.na(v1), 0, integer(0))
  

错误:false的长度必须为1(condition的长度),而不是0       致电rlang::last_error()查看回溯

但是

NA + NA    #[1]不适用

length 1,但仍返回错误

v1 <- NA
if_else(is.na(v1), 0, v1[1] + v1[2])
  

错误:false必须是双精度向量,而不是整数向量       致电rlang::last_error()查看回溯

如果我们使用正确的NA派发产品,则可以使用

v1 <- NA_real_
if_else(is.na(v1), 0, v1[1] + v1[2])
#[1] 0

请注意,这里是type问题。总而言之,如文档中所述,lengthtype应该与if_else

相匹配

底线:当值为NULL时,行为是奇怪的,因为+的输出是长度为0的integer(0)


在这种情况下,我们可以使用if/else代替if_else

purrr::map_dbl(x, ~ if(is.null(.x)) 0 else sum(.x))
#[1] 0 3 7 

在这方面,请使用sum而不是分别调用参数y[[1]]y[[2]],因为这会导致长度不平衡

purrr::map_dbl(x, ~ ifelse(is.null(.x), 0, sum(.x)))
#[1] 0 3 7

请注意,ifelse也要求长度相同,尽管由于值的循环在这里可以使用

  

一个矢量,其长度和属性(包括尺寸和“类别”)与来自“是”或“否”值的测试和数据值相同。

purrr::map_dbl(x, ~ ifelse(is.null(.x), 0, .x[[1]] + .x[[2]]))
#[1] 0 3 7

注意:所有方法都用于检查OP的状况。但是,如果目标是获得结果,则还有其他方法。