R:Return 行,一组列只有一个非 NA 值

R: Return rows with only 1 non-NA value for a set of columns

假设我有一个包含以下数据的 data.table:

colA  colB  colC  result
1     2     3     231
1     NA    2     123
NA    3     NA    345
11    NA    NA    754

我如何使用 dplyrmagrittr 仅 select 以下行:

colA  colB  colC result
NA    3     NA   345
11    NA    NA   754

selection 标准是:A-C 列只有 1 个非 NA 值(即 colA, colB, ColC

我一直找不到类似的问题;猜测这是一个奇怪的情况。

基础 R 选项是

df[apply(df, 1, function(x) sum(!is.na(x)) == 1), ]
#  colA colB colC
#3   NA    3   NA
#4   11   NA   NA

一个dplyr选项是

df %>% filter(rowSums(!is.na(.)) == 1)

更新

针对您的评论,您可以做

df[apply(df[, -ncol(df)], 1, function(x) sum(!is.na(x)) == 1), ]
#  colA colB colC result
#3   NA    3   NA    345
#4   11   NA   NA    754

dplyr

中相同
df %>% filter(rowSums(!is.na(.[-length(.)])) == 1)

假设最后一列是您要忽略的列。


示例数据

df <-read.table(text = "colA  colB  colC
1     2     3
1     NA    2
NA    3     NA
11    NA    NA", header = T)

更新示例数据

df <- read.table(text =
"colA  colB  colC  result
1     2     3     231
1     NA    2     123
NA    3     NA    345
11    NA    NA    754
", header = T)

我认为 filter_at 可以做到这一点,但我没能做到。这是 filterpmap_lgl 的一次尝试,您可以在其中指定 select 中的列范围或按其位置指定或使用其他 tidyselect 辅助变量。

library(dplyr)
library(purrr)

df %>%
  filter(pmap_lgl(select(., colA:colC), ~sum(!is.na(c(...))) == 1))

 #  colA colB colC result
#1   NA    3   NA    345
#2   11   NA   NA    754

数据

df <- structure(list(colA = c(1L, 1L, NA, 11L), colB = c(2L, NA, 3L, 
NA), colC = c(3L, 2L, NA, NA), result = c(231L, 123L, 345L, 754L
)), class = "data.frame", row.names = c(NA, -4L))

另一种选择是 filtermap

library(dplyr)
library(purrr)
df %>% 
    filter(map(select(., starts_with('col')), ~ !is.na(.)) %>% 
              reduce(`+`) == 1)
#    colA colB colC result
#1   NA    3   NA    345
#2   11   NA   NA    754

或者另一种选择是使用 transmute_at

df %>% 
   transmute_at(vars(starts_with('col')), ~ !is.na(.)) %>% 
   reduce(`+`) %>%
   magrittr::equals(1) %>% filter(df, .)
#  colA colB colC result
#1   NA    3   NA    345
#2   11   NA   NA    754

数据

df <- structure(list(colA = c(1L, 1L, NA, 11L), colB = c(2L, NA, 3L, 
NA), colC = c(3L, 2L, NA, NA), result = c(231L, 123L, 345L, 754L
)), class = "data.frame", row.names = c(NA, -4L))