R: Возвращает строки только с 1 значением, отличным от NA, для набора столбцов - PullRequest
0 голосов
/ 16 января 2020

Предположим, у меня есть таблица данных со следующими данными:

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

Как мне использовать dplyr и magrittr, чтобы выбрать только следующие строки:

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

Критерии выбора: только 1 не-NA значение для столбцов A- C (т.е. colA, colB, ColC)

Мне не удалось найти аналогичный вопрос; предполагаю, что это странная ситуация.

Ответы [ 3 ]

4 голосов
/ 16 января 2020

Базовая опция R будет

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

A 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)
1 голос
/ 16 января 2020

Другой вариант - 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

data

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))
0 голосов
/ 16 января 2020

Я думаю, что это было бы возможно с 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))
...