R: удалить столбцы на основе проверки сходства двух столбцов - PullRequest
5 голосов
/ 17 апреля 2011

Ввод

row.no   column2    column3  column4
1        bb         ee       up
2        bb         ee       down
3        bb         ee       up
4        bb         yy       down
5        bb         zz       up

У меня есть правило удалять строки 1 и 2 и 3, так как столбцы 2 и 3 для строк 1, 2 и 3 совпадают, противоречивые данные (up и down) находятся в столбце 4.

Как я могу попросить R удалить те строки с одинаковыми именами в столбцах 2 и 3, но сжимая столбец 3, чтобы получить следующую матрицу:

row.no   column2    column3  column4
4        bb         yy       down
5        bb         zz       up

Ответы [ 4 ]

6 голосов
/ 17 апреля 2011

Функции в пакете plyr действительно сияют при подобных проблемах.Вот решение с использованием двух строк кода.

Настройка данных (любезно предоставлено @GavinSimpson)

dat <- structure(list(row.no = 1:5, column2 = structure(c(1L, 1L, 1L, 
1L, 1L), .Label = "bb", class = "factor"), column3 = structure(c(1L, 
1L, 1L, 2L, 3L), .Label = c("ee", "yy", "zz"), class = "factor"), 
    column4 = structure(c(2L, 1L, 2L, 1L, 2L), .Label = c("down", 
    "up"), class = "factor")), .Names = c("row.no", "column2", 
"column3", "column4"), class = "data.frame", row.names = c(NA, 
-5L))

Загрузка пакета plyr

library(plyr)

Используйте ddply для разделения, анализа и объединения данных.Следующая строка анализа кода разбивает данные на уникальные комбинации (column2 и column3) отдельно.Затем я добавляю столбец с именем unique, который вычисляет количество уникальных значений column4 для каждого набора.Наконец, используйте простое подмножество, чтобы вернуть только те строки, где уникальный == 1, и опустите столбец 5.

df <- ddply(dat, .(column2, column3), transform, 
    row.no=row.no, unique=length(unique(column4)))
df[df$unique==1, -5]

И результаты:

  row.no column2 column3 column4
4      4      bb      yy    down
5      5      bb      zz      up
4 голосов
/ 17 апреля 2011

Вот одно потенциальное, хотя и несколько не элегантное, решение

out <- with(dat, split(dat, interaction(column2, column3)))
out <- lapply(out, function(x) if(NROW(x) > 1) {NULL} else {data.frame(x)})
out <- out[!sapply(out, is.null)]
do.call(rbind, out)

, которое дает:

> do.call(rbind, out)
      row.no column2 column3 column4
bb.yy      4      bb      yy    down
bb.zz      5      bb      zz      up

Некоторые пояснения, строка за строкой:

  • Строка 1: разбивает данные на список, каждый компонент которого представляет собой фрейм данных со строками, соответствующими группам, образованным уникальными комбинациями column2 и column3.
  • Строка 2: перебрать результат из Строки 1;если во фрейме данных более 1 строки, вернуть NULL, если нет, вернуть фрейм данных 1 строки.
  • Строка 3: перебрать выходные данные из Строки 2;возвращать только ненулевые компоненты
  • Строка 4: нужно связать, построчно, вывод из строки 3, который мы организуем через do.call()

Это может быть упрощено до двух строк, объединяя строки 1-3 в одну строку:

out <- lapply(with(dat, split(dat, interaction(column2, column3))),
              function(x) if(NROW(x) > 1) {NULL} else {data.frame(x)})
do.call(rbind, out[!sapply(out, is.null)])

Выше все было сделано с:

dat <- structure(list(row.no = 1:5, column2 = structure(c(1L, 1L, 1L, 
1L, 1L), .Label = "bb", class = "factor"), column3 = structure(c(1L, 
1L, 1L, 2L, 3L), .Label = c("ee", "yy", "zz"), class = "factor"), 
    column4 = structure(c(2L, 1L, 2L, 1L, 2L), .Label = c("down", 
    "up"), class = "factor")), .Names = c("row.no", "column2", 
"column3", "column4"), class = "data.frame", row.names = c(NA, 
-5L))
4 голосов
/ 17 апреля 2011

Гэвин продолжает поднимать планку качества ответов. Вот моя попытка.

# This is one way of importing the data into R
sally <- textConnection("row.no   column2    column3  column4
1        bb         ee       up
2        bb         ee       down
3        bb         ee       up
4        bb         yy       down
5        bb         zz       up")
sally <- read.table(sally, header = TRUE)

# Order the data frame to make rle work its magic
sally <- sally[order(sally$column3, sally$column4), ]

# Find which values are repeating
sally.rle2 <- rle(as.character(sally$column2))
sally.rle3 <- rle(as.character(sally$column3))
sally.rle4 <- rle(as.character(sally$oclumn4))

sally.can.wait2 <- sally.rle2$values[which(sally.rle3$lengths != 1)]
sally.can.wait3 <- sally.rle3$values[which(sally.rle3$lengths != 1)]
sally.can.wait4 <- sally.rle4$values[which(sally.rle4$lengths != 1)]

# Find which lines have values that are repeating
dup <- c(which(sally$column2 == sally.can.wait2),
         which(sally$column3 == sally.can.wait3),
         which(sally$column4 == sally.can.wait4))
dup <- dup[duplicated(dup)]

# Display the lines that have no repeating values
sally[-dup, ]
0 голосов
/ 17 апреля 2011

Вы можете попробовать один из следующих двух способов.Предположим, что таблица называется table1.

Метод 1

repeated_rows = c();
for (i in 1:(nrow(table1)-1)){
  for (j in (i+1):nrow(table1)){
    if (sum((table1[i,2:3] == table1[j,2:3])) == 2){
      repeated_rows = c(repeated_rows, i, j)
    }
  }
}
repeated_rows = unique(repeated_rows)
table1[-repeated_rows,]

Метод 2

duplicates = duplicated(table1[,2:3])
for (i in 1:length(duplicates)){
  if (duplicates[i] == TRUE){
    for (j in 1:nrow(table1)){
      if (sum(table1[i,2:3] == table1[j,2:3]) == 2){
        duplicates[j] = TRUE;
      }
    }
  }
}
table1[!duplicates,]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...