Проверьте, равна ли одна строка любым другим строкам в R

#r #vector

#r #вектор

Вопрос:

У меня есть набор данных с одним столбцом идентификатора, 12 информационными столбцами (строками) и n строками. Это выглядит так:

 ID Col1 Col2 Col3 Col4 Col5 ...
01 a    b    c    d    a
02 a    a    a    a    a
03 b    b    b    b    b
...
  

Мне нужно перейти строка за строкой и проверить, равна ли эта строка (учитывая все ее столбцы) любой другой строке в наборе данных. Моим выводом должны быть два новых столбца: один, указывающий, равна ли эта конкретная строка любой другой строке, и второй столбец, указывающий, какой строке он равен (в случае TRUE в предыдущем столбце)

Я ценю любые предложения.

Комментарии:

1. Является ли ID первичным или уникальным ключом?

2. Не могли бы вы предоставить полный пример фрейма данных с ожидаемым результатом?

3. ID — это уникальный ключ.

Ответ №1:

Предполагая DF , что в примечании в конце, отсортируйте его и создайте столбец dup , указывающий, существует ли предыдущая повторяющаяся строка. Затем установите wx значение равным номеру строки в исходном фрейме данных дубликата. Наконец, вернитесь назад.

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

Вопрос не касается ситуации с более чем 2 одинаковыми строками, но если такая ситуация существует, то каждый дубликат будет указывать на ближайшую предыдущую строку, в которой он является дубликатом.

 o <- do.call("order", DF[-1])
DFo <- DF[o, ]
DFo$wx <- DFo$dup <- duplicated(DFo)
DFo$wx[DFo$dup] <- as.numeric(rownames(DFo))[which(DFo$dup) - 1]
DFo[order(o), ] # back to original order
  

предоставление:

   ID Col1 Col2 Col3 Col4 Col5   dup wx
1  1    a    b    c    d    a FALSE  0
2  2    a    a    a    a    a FALSE  0
3  3    b    b    b    b    b FALSE  0
4  1    a    b    c    d    a  TRUE  1
  

Примечание

 Lines <- "ID Col1 Col2 Col3 Col4 Col5
01 a    b    c    d    a
02 a    a    a    a    a
03 b    b    b    b    b"
DF <- read.table(text = Lines, header = TRUE)
DF <- DF[c(1:3, 1), ]
rownames(DF) <- NULL
  

предоставление:

 > DF
  ID Col1 Col2 Col3 Col4 Col5
1  1    a    b    c    d    a
2  2    a    a    a    a    a
3  3    b    b    b    b    b
4  1    a    b    c    d    a
  

Ответ №2:

С df подобным ниже:

   ID Col1 Col2 Col3 Col4 Col5
1  1    a    b    c    d    a
2  2    a    a    a    a    a
3  3    b    b    b    b    b
4  3    b    b    b    b    b
  

Вы можете попробовать группировку по всем столбцам и проверить, есть ли какие-либо подсчеты > 1 , а также вставить номера строк ( 1:nrow(df) ):

 df <- transform(
  df,
  dupe = ave(ID, mget(names(df)), FUN = length) > 1,
  dupeRows = ave(1:nrow(df), mget(names(df)), FUN = toString)
)
  

Поскольку это даст вам число для каждой строки, даже если дубликатов нет, вы могли бы сделать:

 df$dupeRows <- with(df, 
                    Map(function(x, y) 
                      toString(x[x != y]), 
                      strsplit(as.character(dupeRows), split = ', '), 
                      1:nrow(df)))
  

Вывод:

   ID Col1 Col2 Col3 Col4 Col5  dupe dupeRows
1  1    a    b    c    d    a FALSE         
2  2    a    a    a    a    a FALSE         
3  3    b    b    b    b    b  TRUE        4
4  3    b    b    b    b    b  TRUE        3
  

Данные

 df <- structure(list(ID = c(1L, 2L, 3L, 3L), Col1 = structure(c(1L, 
1L, 2L, 2L), .Label = c("a", "b"), class = "factor"), Col2 = structure(c(2L, 
1L, 2L, 2L), .Label = c("a", "b"), class = "factor"), Col3 = structure(c(3L, 
1L, 2L, 2L), .Label = c("a", "b", "c"), class = "factor"), Col4 = structure(c(3L, 
1L, 2L, 2L), .Label = c("a", "b", "d"), class = "factor"), Col5 = structure(c(1L, 
1L, 2L, 2L), .Label = c("a", "b"), class = "factor")), row.names = c(NA, 
-4L), class = "data.frame")
  

Ответ №3:

Решение dplyr

 library(dplyr)
df %>% 
  mutate(row_num = 1:n(), is_dup = duplicated(df)) %>% 
  group_by(across(-c(row_num, is_dup))) %>% 
  mutate(
    has_copies = n() > 1L, 
    which_row = if_else(is_dup, first(row_num), NA_integer_), 
    row_num = NULL, is_dup = NULL
  )
  

Вывод

 # A tibble: 5 x 8
# Groups:   ID, Col1, Col2, Col3, Col4, Col5 [3]
  ID    Col1  Col2  Col3  Col4  Col5  has_copies which_row
  <chr> <fct> <fct> <fct> <fct> <fct> <lgl>          <int>
1 1     a     b     c     d     a     FALSE             NA
2 2     a     a     a     a     a     FALSE             NA
3 3     b     b     b     b     b     TRUE              NA
4 3     b     b     b     b     b     TRUE               3
5 3     b     b     b     b     b     TRUE               3
  
  1. Для каждой строки, имеющей более одной копии, значение has_copies a TRUE .

  2. Для набора одинаковых строк я рассматриваю первую строку как исходную, а все остальные строки — как дубликаты. В связи с этим, which_row дает вам индекс оригинала для каждого найденного дубликата. Другими словами, если строка не имеет дубликатов или является оригиналом, это дает вам NA .