Пошук ВСІХ повторюваних рядків, включаючи "елементи з меншими підписками"


111

R duplicatedповертає вектор, який показує, чи кожен елемент вектора або фрейму даних є дублікатом елемента з меншим індексом. Отже, якщо рядки 3, 4 і 5 5-рядкового кадру даних однакові, duplicatedце дасть мені вектор

FALSE, FALSE, FALSE, TRUE, TRUE

Але в цьому випадку я насправді хочу отримати

FALSE, FALSE, TRUE, TRUE, TRUE

тобто я хочу знати, чи дублюється рядок рядком з більшим підписом.

Відповіді:


128

duplicatedмає fromLastаргумент. У розділі "Приклад" ?duplicatedпоказано, як ним користуватися. Просто зателефонуйте duplicatedдвічі, один раз з fromLast=FALSEі один раз разом fromLast=TRUEі займіть рядки там, де є TRUE.


Кілька пізніх редагувань: Ви не надали відтворюваного прикладу, ось ось ілюстрація, яку люб’язно написав @jbaums

vec <- c("a", "b", "c","c","c") 
vec[duplicated(vec) | duplicated(vec, fromLast=TRUE)]
## [1] "c" "c" "c"

Редагувати: І приклад для випадку кадру даних:

df <- data.frame(rbind(c("a","a"),c("b","b"),c("c","c"),c("c","c")))
df[duplicated(df) | duplicated(df, fromLast=TRUE), ]
##   X1 X2
## 3  c  c
## 4  c  c

3
Тримайся, я щойно пройшов тест і виявив, що я помилявся: x <- c(1:9, 7:10, 5:22); y <- c(letters, letters[1:5]); test <- data.frame(x, y); test[duplicated(test$x) | duplicated(test$x, fromLast=TRUE), ]повернув усі три копії 7, 8 та 9. Чому це працює?
JoeM05

1
Тому що середні захоплюються незалежно від того, починаючи з кінця чи спереду. Наприклад, duplicated(c(1,1,1))vs duplicated(c(1,1,1,), fromLast = TRUE)дає c(FALSE,TRUE,TRUE)і c(TRUE,TRUE,FALSE). Середнє значення є TRUEв обох випадках. Прийняття |обох векторів дає c(TRUE,TRUE,TRUE).
Брендон

34

Вам потрібно зібрати набір duplicatedзначень, застосувати uniqueта протестувати за допомогою %in%. Як завжди, зразок проблеми змусить цей процес ожити.

> vec <- c("a", "b", "c","c","c")
> vec[ duplicated(vec)]
[1] "c" "c"
> unique(vec[ duplicated(vec)])
[1] "c"
>  vec %in% unique(vec[ duplicated(vec)]) 
[1] FALSE FALSE  TRUE  TRUE  TRUE

Погодьтеся. Можливо, навіть сповільнити обробку, але навряд чи це дуже сповільнить.
IRTFM

Цілком правда. ОП не запропонував приклад даних для тестування на "колись повторювані" рядки у кадрі даних. Я думаю, що моя пропозиція використовувати duplicated, uniqueі %in%її легко можна було б узагальнити до фрейму даних, якби вперше pasteкожен рядок був з незвичайним розділовим символом. (Прийнята відповідь краща.)
IRTFM

3

У мене було те саме питання , і якщо я не помиляюся, це теж відповідь.

vec[col %in% vec[duplicated(vec$col),]$col]

Незважаючи на те, який з них швидший, набір даних, який я зараз використовую, недостатньо великий, щоб зробити тести, які дають значні пробіли у часі.


1
Здається, ця відповідь використовує vecі атомний вектор, і як кадр даних. Я підозрюю, що з фактичним датрамфреймом він не зможе.
IRTFM

3

Дублювання рядків у кадрі даних можна отримати за dplyrдопомогою виконання

df = bind_rows(iris, head(iris, 20)) # build some test data
df %>% group_by_all() %>% filter(n()>1) %>% ungroup()

Для виключення певних стовпців group_by_at(vars(-var1, -var2))можна використовувати замість того, щоб групувати дані.

Якщо потрібні індекси рядків, а не лише дані, ви можете додати їх спочатку як у:

df %>% add_rownames %>% group_by_at(vars(-rowname)) %>% filter(n()>1) %>% pull(rowname)

1
Гарне використання n(). Не забудьте розгрупувати отриманий кадр даних.
qwr

@qwr Я скоригував відповідь, щоб розгрупувати результат
Holger Brandl

2

Ось рішення @Joshua Ulrich як функція. Цей формат дозволяє використовувати цей код таким же чином, як і ви дублювали ():

allDuplicated <- function(vec){
  front <- duplicated(vec)
  back <- duplicated(vec, fromLast = TRUE)
  all_dup <- front + back > 0
  return(all_dup)
}

Використовуючи той же приклад:

vec <- c("a", "b", "c","c","c") 
allDuplicated(vec) 
[1] FALSE FALSE  TRUE  TRUE  TRUE

0

Якщо вас цікавить, які рядки дублюються для певних стовпців, ви можете використовувати підхід plyr :

ddply(df, .(col1, col2), function(df) if(nrow(df) > 1) df else c())

Додавання змінної підрахунку за допомогою dplyr :

df %>% add_count(col1, col2) %>% filter(n > 1)  # data frame
df %>% add_count(col1, col2) %>% select(n) > 1  # logical vector

Для повторюваних рядків (враховуючи всі стовпці):

df %>% group_by_all %>% add_tally %>% ungroup %>% filter(n > 1)
df %>% group_by_all %>% add_tally %>% ungroup %>% select(n) > 1

Перевага цих підходів полягає в тому, що ви можете вказати кількість дублікатів як обрізання.


0

У мене була схожа проблема, але мені потрібно було ідентифікувати повторювані рядки за значеннями в конкретних стовпцях. Я придумав таке рішення dplyr :

df <- df %>% 
  group_by(Column1, Column2, Column3) %>% 
  mutate(Duplicated = case_when(length(Column1)>1 ~ "Yes",
                            TRUE ~ "No")) %>%
  ungroup()

Код групує рядки за певними стовпцями. Якщо довжина групи більша за 1, код позначає всі рядки групи як дублювані. Після цього ви можете використовувати Duplicatedстовпчик для фільтрування тощо.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.