Хотите удалить дублированные строки, если в столбцах нет значения NA - PullRequest
1 голос
/ 26 апреля 2019

У меня есть таблица данных с 4 столбцами: ID, Имя, Rate1, Rate2.

Я хочу удалить дубликаты, где ID, Rate1 и Rate 2 совпадают, , но если они оба NA, я хотел бы сохранить обе строки.

По сути, я хочу условно удалить дубликаты, но только если условия! = NA.

Например, я бы хотел, чтобы это было:

ID   Name   Rate1    Rate2
1    Xyz    1        2
1    Abc    1        2
2    Def    NA       NA
2    Lmn    NA       NA
3    Hij    3        5
3    Qrs    3        7

, чтобы стать таким:

ID   Name   Rate1    Rate2
1    Xyz    1        2
2    Def    NA       NA
2    Lmn    NA       NA
3    Hij    3        5
3    Qrs    3        7

Заранее спасибо!

РЕДАКТИРОВАТЬ: Я знаюМожно просто взять подмножество таблицы данных, где Rates - это NA, затем удалить дубликаты слева, а затем добавить обратно строки NA - но я бы предпочел избежать этой стратегии.Это потому, что на самом деле существует довольно много парных ставок, для которых я хочу сделать это последовательно.

EDIT2: добавлено еще несколько строк в пример для ясности.

1 Ответ

4 голосов
/ 26 апреля 2019
Опция

A base R будет заключаться в использовании duplicated для подмножества набора данных без столбца «Имя», т.е. столбца с индексом 2, для создания логического вектора, отрицание (! - TRUE становится FALSE и наоборот), так чтоИСТИНА будет недублированных строк.Наряду с этим создайте еще одно условие с rowSums в логической матрице (is.na(df1[3:4]) - столбцы оценки), чтобы получить строки, которые все являются NA - здесь мы сравниваем его с 2 - то есть числом столбцов оценки в наборе данных).Оба условия объединяются | для создания ожидаемого логического индекса

i1 <- !duplicated(df1[-2])| rowSums(is.na(df1[3:4])) == 2
df1[i1,]
#    ID Name Rate1 Rate2
#1  1  Xyz     1     2
#3  2  Def    NA    NA
#4  2  Lmn    NA    NA

или с Reduce из base R

df1[Reduce(`&`, lapply(df1[3:4], is.na)) | !duplicated(df1[-2]), ]

Оборачивая его в функцию

f1 <- function(dat, i, method ) {     

         nm1 <- grep("^Rate", colnames(dat), value = TRUE)    
         i1 <- !duplicated(dat[-i])  
         i2 <-  switch(method, 
           "rowSums" = rowSums(is.na(dat[nm1])) == length(nm1),
           "Reduce" = Reduce(`&`, lapply(dat[nm1], is.na))

         )   
         i3 <- i1|i2
         dat[i3,]
     }    

-testing

f1(df1, 2, "rowSums")
#  ID Name Rate1 Rate2
#1  1  Xyz     1     2
#3  2  Def    NA    NA
#4  2  Lmn    NA    NA

f1(df1, 2, "Reduce")
#  ID Name Rate1 Rate2
#1  1  Xyz     1     2
#3  2  Def    NA    NA
#4  2  Lmn    NA    NA

f1(df2, 2, "rowSums")
#  ID Name Rate1 Rate2
#1  1  Xyz     1     2
#3  2  Def    NA    NA
#4  2  Lmn    NA    NA
#5  3  Hij     3     5
#6  3  Qrs     3     7

f1(df2, 2, "Reduce")
#  ID Name Rate1 Rate2
#1  1  Xyz     1     2
#3  2  Def    NA    NA
#4  2  Lmn    NA    NA
#5  3  Hij     3     5
#6  3  Qrs     3     7

, если имеется несколько столбцов «Rate» (скажем, 100 или более - единственное, что нужно изменить в первом решении, это 2, должно быть заменено на числоСтолбцы 'Rate')


или с использованием tidyverse

library(tidyvesrse)
df1 %>%
    group_by(ID) %>%
    filter_at(vars(Rate1, Rate2), any_vars(!duplicated(.)|is.na(.)))
# A tibble: 3 x 4
# Groups:   ID [2]
#     ID Name  Rate1 Rate2
#  <int> <chr> <int> <int>
#1     1 Xyz       1     2
#2     2 Def      NA    NA
#3     2 Lmn      NA    NA



df2 %>% 
     group_by(ID) %>%
     filter_at(vars(Rate1, Rate2), any_vars(!duplicated(.)|is.na(.)))
# A tibble: 5 x 4
# Groups:   ID [3]
#     ID Name  Rate1 Rate2
#  <int> <chr> <int> <int>
#1     1 Xyz       1     2
#2     2 Def      NA    NA
#3     2 Lmn      NA    NA
#4     3 Hij       3     5
#5     3 Qrs       3     7

data

df1 <- structure(list(ID = c(1L, 1L, 2L, 2L), Name = c("Xyz", "Abc", 
"Def", "Lmn"), Rate1 = c(1L, 1L, NA, NA), Rate2 = c(2L, 2L, NA, 
 NA)), class = "data.frame", row.names = c(NA, -4L))

df2 <- structure(list(ID = c(1L, 1L, 2L, 2L, 3L, 3L), Name = c("Xyz", 
 "Abc", "Def", "Lmn", "Hij", "Qrs"), Rate1 = c(1L, 1L, NA, NA, 
 3L, 3L), Rate2 = c(2L, 2L, NA, NA, 5L, 7L)), class = "data.frame", 
 row.names = c(NA, -6L))
...