R: Как удалить строки, которые отличаются от другой строки только в один (два, три) столбца? - PullRequest
0 голосов
/ 05 июля 2018

У меня есть кадр данных, похожий на следующий пример. Иногда строки содержат ту же информацию об объекте, что и в другой строке, за исключением одного (или нескольких) столбцов, которые содержат «NA». Мне нужны только строки с максимально возможной информацией, поэтому я хочу удалить все строки, которые содержат «NA», но в остальном имеют ту же информацию, что и другая строка. «NA» может быть в столбце C или D или в обоих (никогда не в A или B). Если нет «более точной» строки, строка, содержащая «NA», должна остаться.

Я пробовал это использовать цикл for (см. Пример), и он работает, строки 1 и 6 будут удалены. Однако мне пришлось бы настроить его так, чтобы он также проверял столбец C, и в моих реальных данных у меня есть еще несколько столбцов и, следовательно, несколько возможных комбинаций, что делает это решение непрактичным и может привести к ошибкам.

Есть ли другой способ легко решить эту проблему? Спасибо!

df <- rbind(data.frame(A = "obj1", B = "1", C = "2", D = "NA"), 
            data.frame(A = "obj1", B = "1", C = "2", D = "3"),
            data.frame(A = "obj2", B = "1", C = "NA", D = "3"),
            data.frame(A = "obj2", B = "1", C = "2", D = "3"),
            data.frame(A = "obj2", B = "3", C = "2", D = "3"),
            data.frame(A = "obj2", B = "3", C = "2", D = "NA"),
            data.frame(A = "obj3", B = "2", C = "4", D = "6"),
            data.frame(A = "obj4", B = "2", C = "NA", D = "NA"))

toBeDeleted <- c(55)

for (i in 1:nrow(df)){
  thisRow <- df[i,]

  if (thisRow$D == "NA"){
    for (j in i:nrow(subset(df, A == thisRow$A))){
      anotherRow <- df[j,]
      if (anotherRow$A == thisRow$A & anotherRow$B == thisRow$B 
          & anotherRow$C == thisRow$C & anotherRow$D != thisRow$D){
        toBeDeleted <- c(toBeDeleted,i)
      }
    }
  }
}

df2 <- df[-toBeDeleted,]

1 Ответ

0 голосов
/ 05 июля 2018

Мы можем использовать комбинацию duplicated(df[1:2]) и duplicated(df[1:2], fromLast = TRUE) вместе с rowSums(is.na(df)) > 0, чтобы исключить все строки, которые имеют NA и являются дубликатами:

df <- rbind(data.frame(A = "obj1", B = "1", C = "2", D = NA), 
            data.frame(A = "obj1", B = "1", C = "2", D = "3"),
            data.frame(A = "obj2", B = "1", C = NA, D = "3"),
            data.frame(A = "obj2", B = "1", C = "2", D = "3"),
            data.frame(A = "obj2", B = "3", C = "2", D = "3"),
            data.frame(A = "obj2", B = "3", C = "2", D = NA),
            data.frame(A = "obj3", B = "2", C = "4", D = "6"),
            data.frame(A = "obj4", B = "2", C = NA, D = NA))

df[!((duplicated(df[1:2]) | duplicated(df[1:2], fromLast = TRUE)) & rowSums(is.na(df)) > 0),]

     A B    C    D
2 obj1 1    2    3
4 obj2 1    2    3
5 obj2 3    2    3
7 obj3 2    4    6
8 obj4 2 <NA> <NA>

Это простое подмножество, поэтому цикл не нужен, и он очень быстрый даже при огромных данных. Это работает так:

Мы называем данные df[] и исключаем с помощью !() все строки, имеющие дубликаты в первых двух столбцах df[1:2] и имеющие хотя бы одно значение NA rowSums(is.na(df)) > 0. Чтобы это работало, вам нужны настоящие NA в ваших данных, а не character "NA", которые были в данных вашего примера выше. Если у вас есть только "NA", используйте rowSums(df == "NA") > 0.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...