Найти индексы дублированных строк

Функция, дублируемая в R, выполняет поиск дубликатов строк. Если мы хотим удалить дубликаты, нам нужно просто написать df[!duplicated(df),], и дубликаты будут удалены из фрейма данных.

Но как найти индексы дублированных данных? Если duplicated возвращает TRUE в некоторой строке, это означает, что это второе появление такой строки в кадре данных, и его индекс может быть легко получен. Как получить индекс первого появления этой строки? Или, другими словами, индекс, с которым дублированная строка идентична?

Я мог бы создать цикл на data.frame, но я думаю, что есть более элегантный ответ на этот вопрос.

Ответ 1

Возвращает вектор логического индекса:

duplicated(df) | duplicated(df[nrow(df):1, ])[nrow(df):1]

Вот пример:

df <- data.frame(a = c(1,2,3,4,1,5,6,4,2,1))

duplicated(df) | duplicated(df[nrow(df):1, ])[nrow(df):1]
#[1]  TRUE  TRUE FALSE  TRUE  TRUE FALSE FALSE  TRUE  TRUE  TRUE

which(duplicated(df) | duplicated(df[nrow(df):1, ])[nrow(df):1])
#[1]  1  2  4  5  8  9 10

Обновить (на основе комментария):
Сложность команды может быть уменьшена, если fromLast = TRUE используется как аргумент функции. Это проще, чем создание двух обратных векторов.

duplicated(df) | duplicated(df, fromLast = TRUE)

duplicated(df) | duplicated(df, fromLast = TRUE)
#[1]  TRUE  TRUE FALSE  TRUE  TRUE FALSE FALSE  TRUE  TRUE  TRUE

Как это работает?

Функция duplicated применяется как к исходному кадру данных, так и к кадру данных с обратным порядком строк. Выход последнего снова отменяется. Обратите внимание, что первые вхождения дублированных значений в исходные данные являются последними вхождениями в обратную версию. Затем оба вектора объединяются с использованием |, так как a TRUE по меньшей мере в одном из них указывает дублируемое значение.

Ответ 2

Если вы используете ключевую таблицу data.table, вы можете использовать следующий элегантный синтаксис

library(data.table)
DT <- data.table(A = rep(1:3, each=4), 
                 B = rep(1:4, each=3), 
                 C = rep(1:2, 6), key = "A,B,C")

DT[unique(DT[duplicated(DT)]),which=T]

Чтобы распаковать

  • DT[duplicated(DT)] подмножества этих строк, которые являются дубликатами.

  • unique(...) возвращает только уникальные комбинации дублированных строк. Это касается любых случаев с более чем одним дубликатом (дубликаты дубликатов, например, три раза и т.д.)

  • DT[..., which = T] объединяет повторяющиеся строки с оригиналом, при этом which=T возвращает номер строки (без which = T он просто возвращает данные).

Вы также можете использовать

 DT[,count := .N,by = list(A,B,C)][count>1, which=T]