有没有一种R函数可以执行与dplyr :: coalesce()相反的操作?

3

调用dplyr::coalesce会返回第一个非缺失值:

> vec1 <- c(11, 12, NA, NA, NA)
> vec2 <- c(21, 22, NA, NA, 25)
> vec3 <- c(NA, 32, NA, 34, 35)
> coalesce(vec1, vec2, vec3)
[1] 11 12 NA 34 25

是否有类似于调用 vec1 | vec2 | vec3 的函数(返回值而不是逻辑值)?

类似于 vec1 & vec2 & vec3 的函数,当没有缺失值时返回最后一个值?这种情况经常出现,但我找不到一种简洁/简单的方法来实现它。

> vec1 <- c(11, 12, NA, NA, NA)
> vec2 <- c(21, 22, NA, NA, 25)
> vec3 <- c(NA, 32, NA, 34, 35)
> ideal_fn(vec1, vec2, vec3)
[1] NA 32 NA NA NA

对于数字和逻辑值,我可以使用vec3[vec1 & vec2 & vec3]ifelse(vec1 & vec2, vec3)来轻松/简洁完成此操作。但它们不能用于字符向量。
有比ifelse(!is.na(vec1) & !is.na(vec2) & !is.na(vec3), vec3, NA)更好的方法吗?这似乎是解决非常简单问题的非常迂回的方法。
2个回答

2
我们可以在不使用na.rm的情况下使用pmax函数。"最初的回答"。
pmax(vec1, vec2, vec3)
#[1] NA 32 NA NA NA

另一个选择是使用max.colties.method = 'last'。创建一个由向量组成的矩阵或数据框,然后应用max.col以获取每行中最大值的列索引,与行序列cbind并提取相应的值。如果一行只有NA,则列索引将为NA,因此得到NA
m1 <- cbind(vec1, vec2, vec3)
m1[cbind(seq_len(nrow(m1)), max.col(m1, 'last'))]
#[1] NA 32 NA NA NA

如果这是基于位置而不是最大值。最初的回答。
m2 <- col(m1) * NA^is.na(m1)
m1[cbind(seq_len(nrow(m1)), max.col(m2, 'last'))]
#[1] NA 32 NA NA NA

如果有更多的向量,另一个选项是使用Reduce创建逻辑向量。

原始答案翻译成中文为“最初的回答”。

i1 <- Reduce(`|`, lapply(mget(paste0("vec", 1:3)), is.na))
replace(vec3, i1, NA)
#[1] NA 32 NA NA NA

或者使用rowSums函数

vec3 * NA^!!rowSums(is.na(cbind(vec1, vec2, vec3)))
#[1] NA 32 NA NA NA

注意:两者都是基本的R函数。最初的回答。

很遗憾,它是基于位置的,所以 pmax 无法使用。我认为我仍然会选择 ifelse(!is.na(vec1) & !is.na(vec2) & !is.na(vec3), vec3, NA) 而不是选项2,因为它更容易阅读。 - Nick
@Nick 如果是基于位置的话,我也已经编辑了那个情况。请阅读整个解决方案而不是只看第一个部分。如果你有超过10个向量,那么你可以将&更改为i1 <- Reduce('&',!lapply(mget(paste0("vec", 1:3)),is.na)); ifelse(i1,vec3,NA) - akrun

0

我瞎搞了一下,发现使用tidyverse有更简洁的方法:

and_values <- . %>%
  reduce(~ ifelse(is.na(.x), NA, .y))

> and_values(list(vec1, vec2, vec3))
[1] NA 32 NA NA NA

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接