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
我如何使用 dplyr
和 magrittr
仅 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
可以做到这一点,但我没能做到。这是 filter
和 pmap_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))
另一种选择是 filter
和 map
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))
假设我有一个包含以下数据的 data.table:
colA colB colC result
1 2 3 231
1 NA 2 123
NA 3 NA 345
11 NA NA 754
我如何使用 dplyr
和 magrittr
仅 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
可以做到这一点,但我没能做到。这是 filter
和 pmap_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))
另一种选择是 filter
和 map
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))