简体   繁体   English

在purrr中使用dplyr :: if_else

[英]Using dplyr::if_else with purrr

I am trying to use purrr::map_dbl on a list where I want different behavior if the list element is NULL . 我正在尝试在列表上使用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]) })

This does not work as expected, instead giving the error: 这不能按预期方式工作,而是出现错误:

Error: false must be length 1 (length of condition ), not 0 错误: false必须为长度1( condition长度),而不是0

Debugging the if_else call, I see that y[1] + y[2] is evaluated to integer(0) . 调试if_else调用后,我看到y[1] + y[2]integer(0) Why doesn't this work? 为什么不起作用?

The following all work as I would expect: 我期望以下所有工作:

> 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

What is different about the original call? 原始通话有何不同?

An alternative is to use the na.rm argument in sum to ignore NA or NULL values when adding values together. 另一种选择是在将值加在一起时,使用sumna.rm参数忽略NANULL值。 This way we can skip the if else logic: 这样,我们可以跳过if else逻辑:

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

Here is the Base R equivalent (as pointed out by akrun): 这是Base R的等效项(如akrun所指出):

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

We can debug, it easily with browser() 我们可以使用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

So, here the length is the issue. 因此,这里的length就是问题。

According to ?if_else , requires all arguments to have the same length 根据?if_else ,要求所有参数具有相同的长度

Values to use for TRUE and FALSE values of condition. 用于条件的TRUE和FALSE值的值。 They must be either the same length as condition, or length 1. They must also be the same type: if_else() checks that they have the same type and same class. 它们的长度必须与条件相同,或者长度为1。它们还必须具有相同的类型:if_else()检查它们是否具有相同的类型和相同的类。 All other attributes are taken from true. 所有其他属性均取自true。


To dig further into the issue, it still works if the value is not NULL 要进一步研究问题,如果该值不为NULL ,它仍然可以使用

v1 <- 1
if_else(v1==1, 0, v1[1] + v1[2])
#[1] 0

But, as soon as we change it to NA or NULL , it becomes an issue, could be due to the type 但是,一旦我们将其更改为NANULL ,它就成为问题,可能是由于type

@CBraun made an interesting observation @CBraun做了一个有趣的观察

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

returns length 0, 返回长度为0,

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

Error: false must be length 1 (length of condition ), not 0 Call rlang::last_error() to see a backtrace 错误: false长度必须为1( condition长度),而不是0调用rlang::last_error()以查看回溯

However, 然而,

NA + NA #[1] NA NA + NA#[1] NA

is of length 1, but still returns error length 1,但仍返回错误

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

Error: false must be a double vector, not an integer vector Call rlang::last_error() to see a backtrace 错误: false必须是双rlang::last_error()向量,而不是整数向量调用rlang::last_error()以查看回溯

If we use the correct NA dispatched, it works 如果我们使用正确的NA ,则可以使用

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

Notice that here it is the type issue. 请注意,这是type问题。 All in all, as mentioned in the documentation, length and type should match for if_else 总而言之,如文档中所述, lengthtype应与if_else匹配

Bottomline: When the value is NULL , the behavior is strange because of the output of + is integer(0) of length 0 底线:当值为NULL ,行为是奇怪的,因为+的输出是长度为0的integer(0)


It is a case where we can use if/else instead of if_else 在这种情况下,我们可以使用if/else代替if_else

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

In that respect, use the sum instead of calling the arguments separately y[[1]] , y[[2]] as this cause imbalance in the length 在这方面,请使用sum而不要分别调用y[[1]]y[[2]]因为这会导致长度不平衡

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

Note that ifelse also requires the lengths to be same, though it works here due to recycling of values 请注意, ifelse也要求长度相同,尽管由于值的循环在这里起作用

A vector of the same length and attributes (including dimensions and "class") as test and data values from the values of yes or no. 一个矢量,其长度和属性(包括尺寸和“类别”)与来自“是”或“否”值的测试值和数据值相同。

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

NOTE: All the methods are used to check the OP's condition. 注意:所有方法均用于检查OP的状况。 But, if the objective is to get the result, there are other ways. 但是,如果目标是获得结果,则还有其他方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM