Trovare TUTTE le righe duplicate, inclusi "elementi con pedici più piccoli"


111

R duplicatedrestituisce un vettore che mostra se ogni elemento di un vettore o di un data frame è un duplicato di un elemento con un pedice più piccolo. Quindi se le righe 3, 4 e 5 di un data frame a 5 righe sono le stesse, duplicatedmi darà il vettore

FALSE, FALSE, FALSE, TRUE, TRUE

Ma in questo caso voglio davvero ottenere

FALSE, FALSE, TRUE, TRUE, TRUE

cioè, voglio sapere se una riga è duplicata anche da una riga con un pedice più grande .

Risposte:


128

duplicatedha un fromLastargomento. La sezione "Esempio" di ?duplicatedmostra come usarlo. Chiama duplicateddue volte, una volta con fromLast=FALSEe una volta con fromLast=TRUEe prendi le righe in cui si trovano TRUE.


Qualche modifica tardiva: non hai fornito un esempio riproducibile, quindi ecco un'illustrazione gentilmente fornita da @jbaums

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

Modifica: e un esempio per il caso di un frame di dati:

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
Aspetta, ho appena eseguito un test e ho scoperto di essermi sbagliato: ho 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), ]restituito tutte e tre le copie di 7, 8 e 9. Perché funziona?
JoeM05

1
Perché quelli centrali vengono catturati, non importa se inizi dalla fine o dal davanti. Ad esempio, duplicated(c(1,1,1))vs duplicated(c(1,1,1,), fromLast = TRUE)c(FALSE,TRUE,TRUE)e c(TRUE,TRUE,FALSE). Il valore medio è TRUEin entrambi i casi. La presa |di entrambi i vettori dà c(TRUE,TRUE,TRUE).
Brandon

34

È necessario assemblare il set di duplicatedvalori, applicare uniquee quindi testare con %in%. Come sempre, un problema di esempio renderà vivo questo processo.

> 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

Essere d'accordo. Potrebbe anche rallentare l'elaborazione, ma è improbabile che lo rallenti molto.
IRTFM

Abbastanza vero. L'OP non ha offerto un esempio di dati per testare le righe "mai duplicate" in un dataframe. Credo mio suggerimento di utilizzo duplicated, uniquee %in%potrebbe facilmente essere generalizzato a un dataframe se si dovesse prima pasteogni riga con un carattere separatore insolito. (La risposta accettata è migliore.)
IRTFM

3

Ho avuto la stessa domanda e, se non sbaglio, anche questa è una risposta.

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

Non so quale sia più veloce, però, il set di dati che sto attualmente utilizzando non è abbastanza grande per eseguire test che producono intervalli di tempo significativi.


1
Questa risposta sembra essere utilizzata vecsia come vettore atomico che come dataframe. Ho il sospetto che con un datframe effettivo fallirebbe.
IRTFM

3

È possibile ottenere righe duplicate in un dataframe dplyreseguendo

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

Per escludere determinate colonne group_by_at(vars(-var1, -var2))potrebbe essere utilizzato invece per raggruppare i dati.

Se sono effettivamente necessari gli indici di riga e non solo i dati, è possibile aggiungerli prima come in:

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

1
Buon uso di n(). Non dimenticare di separare il dataframe risultante.
qwr

@qwr ho modificato la risposta per separare il risultato
Holger Brandl

2

Ecco la soluzione di @Joshua Ulrich come funzione. Questo formato ti consente di utilizzare questo codice nello stesso modo in cui useresti duplicated ():

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

Utilizzando lo stesso esempio:

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

0

Se sei interessato a quali righe vengono duplicate per determinate colonne, puoi utilizzare un approccio plyr :

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

Aggiunta di una variabile di conteggio con dplyr :

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

Per righe duplicate (considerando tutte le colonne):

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

Il vantaggio di questi approcci è che puoi specificare quanti duplicati come interruzione.


0

Ho avuto un problema simile ma avevo bisogno di identificare le righe duplicate per valori in colonne specifiche. Ho trovato la seguente soluzione dplyr :

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

Il codice raggruppa le righe per colonne specifiche. Se la lunghezza di un gruppo è maggiore di 1, il codice contrassegna tutte le righe del gruppo come duplicate. Una volta fatto, puoi usare la Duplicatedcolonna per filtrare ecc.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.