Как удалить строки с NAs в определенном столбце, но только если у них есть дубликат в другом столбце?

#r

#r

Вопрос:

Итак, у меня есть этот фрейм данных, в котором некоторые строки дублируются в столбце «Виды», а некоторые нет. NAs есть во всех типах строк, как дублированных, так и не дублированных.

 Species            |  A  |  B  |  
--------------------------------
Tilapia guineensis |  1  |  10 |  
Tilapia guineensis |  1  |  NA |   
Tilapia zillii     |  3  |  23 |  
Tilapia zillii     |  3  |  NA |  
Eutrigla gurnardus | 18  |  4  |
Caramila artida    |  9  |  NA |  
Sprattus sprattus  |  7  |  6  |
Spalili burcant    | 11  |  NA |
 

Я хочу удалить те строки, в которых есть NAs в столбце B, но только если они принадлежат к повторяющейся строке.
Мой вывод будет примерно таким:

 Species            |  A  |  B  |  
--------------------------------
Tilapia guineensis |  1  |  10 |    
Tilapia zillii     |  3  |  23 |    
Eutrigla gurnardus | 18  |  4  |
Caramila artida    |  9  |  NA |  
Sprattus sprattus  |  7  |  6  |
Spalili burcant    | 11  |  NA |
 

В принципе, если строка дублируется в столбце Species и имеет NA в столбце B, я хочу удалить эту строку с NA. Однако, если строка уникальна в столбце Species, я хочу сохранить ее, даже если в ней есть NA.

Извините, если я сбиваю с толку, заранее спасибо.

Воспроизводимый формат данных:

 df <- read.csv(text="
Species,A,B
Tilapia guineensis,1,10
Tilapia guineensis,1,NA
Tilapia zillii,3,23
Tilapia zillii,3,NA
Eutrigla gurnardus,18,4
Caramila artida,9,NA
Sprattus sprattus,7,6
Spalili burcant,11,NA")
 

Ответ №1:

Я думаю, вы можете избежать использования какой-либо логики группировки и получить результат за один проход:

 df[!(duplicated(df$Species) amp; is.na(df$B)),]
#             Species  A  B
#1 Tilapia guineensis  1 10
#3     Tilapia zillii  3 23
#5 Eutrigla gurnardus 18  4
#6    Caramila artida  9 NA
#7  Sprattus sprattus  7  6
#8    Spalili burcant 11 NA
 

Ответ №2:

Вы можете выбрать строку, если для or есть только 1 строка Species , если это не NA значение.

 library(dplyr)
df %>% group_by(Species) %>% filter(n() == 1 | !is.na(B))

#  Species                A     B
#  <chr>              <int> <int>
#1 Tilapia guineensis     1    10
#2 Tilapia zillii         3    23
#3 Eutrigla gurnardus    18     4
#4 Caramila artida        9    NA
#5 Sprattus sprattus      7     6
#6 Spalili burcant       11    NA
 

Вы также можете написать ту же логику в base R и data.table :

 #Base R
subset(df, ave(!is.na(B), Species, FUN = function(x) length(x) == 1 | x))

#data.table
library(data.table)
setDT(df)[, .SD[.N == 1 | !is.na(B)], Species]
 

данные

 df <- structure(list(Species = c("Tilapia guineensis", "Tilapia guineensis", 
"Tilapia zillii", "Tilapia zillii", "Eutrigla gurnardus", "Caramila artida", 
"Sprattus sprattus", "Spalili burcant"), A = c(1L, 1L, 3L, 3L, 
18L, 9L, 7L, 11L), B = c(10L, NA, 23L, NA, 4L, NA, 6L, NA)), row.names = c(NA, 
-8L), class = "data.frame")