Finden ALLER doppelten Zeilen, einschließlich "Elemente mit kleineren Indizes"

110

Rs duplicatedgibt einen Vektor zurück, der zeigt, ob jedes Element eines Vektors oder Datenrahmens ein Duplikat eines Elements mit einem kleineren Index ist. Wenn also die Zeilen 3, 4 und 5 eines 5-Zeilen-Datenrahmens gleich sind, duplicatederhalte ich den Vektor

FALSE, FALSE, FALSE, TRUE, TRUE

Aber in diesem Fall möchte ich eigentlich bekommen

FALSE, FALSE, TRUE, TRUE, TRUE

Das heißt, ich möchte wissen, ob eine Zeile auch von einer Zeile mit einem größeren Index dupliziert wird .

Lauren Samuels
quelle

Antworten:

127

duplicatedhat ein fromLastArgument. Der Abschnitt "Beispiel" von ?duplicatedzeigt Ihnen, wie Sie es verwenden. Rufen Sie einfach duplicatedzweimal an, einmal mit fromLast=FALSEund einmal mit fromLast=TRUEund nehmen Sie die Zeilen, wo beide sind TRUE.


Einige späte Änderungen: Sie haben kein reproduzierbares Beispiel angegeben. Hier ist eine Illustration, die freundlicherweise von @jbaums beigesteuert wurde

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

Bearbeiten: Und ein Beispiel für den Fall eines Datenrahmens:

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
Joshua Ulrich
quelle
3
Warte, ich habe gerade einen Test durchgeführt und festgestellt, dass ich falsch lag: 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), ]Alle drei Kopien von 7, 8 und 9 zurückgegeben. Warum funktioniert das?
JoeM05
1
Weil die mittleren erfasst werden, egal ob Sie am Ende oder von vorne beginnen. Zum Beispiel duplicated(c(1,1,1))vs duplicated(c(1,1,1,), fromLast = TRUE)gibt c(FALSE,TRUE,TRUE)und c(TRUE,TRUE,FALSE). Der mittlere Wert ist TRUEin beiden Fällen. Das Nehmen |beider Vektoren ergibt c(TRUE,TRUE,TRUE).
Brandon
34

Sie müssen den Wertesatz zusammenstellen duplicated, anwenden uniqueund dann mit testen %in%. Wie immer wird ein Beispielproblem diesen Prozess zum Leben erwecken.

> 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
quelle
Zustimmen. Könnte sogar die Verarbeitung verlangsamen, aber es ist unwahrscheinlich, dass sie sehr stark verlangsamt wird.
IRTFM
Ziemlich wahr. Das OP bot kein Datenbeispiel zum Testen auf "jemals duplizierte" Zeilen in einem Datenrahmen an. Ich denke , dass mein Vorschlag der Verwendung duplicated, uniqueund %in%leicht zu einem Datenrahmen verallgemeinert werden könnte , wenn man zuerst waren pastemit einem ungewöhnlichen Trennzeichen jede Zeile. (Die akzeptierte Antwort ist besser.)
IRTFM
3

Ich hatte die gleiche Frage , und wenn ich mich nicht irre, ist dies auch eine Antwort.

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

Keine Ahnung, welches schneller ist. Der Datensatz, den ich derzeit verwende, ist jedoch nicht groß genug, um Tests durchzuführen, die erhebliche Zeitlücken verursachen.

François M.
quelle
1
Diese Antwort scheint vecsowohl als Atomvektor als auch als Datenrahmen zu dienen. Ich vermute, dass es mit einem tatsächlichen Datenrahmen fehlschlagen würde.
IRTFM
3

Durch Ausführen von können doppelte Zeilen in einem Datenrahmen erhalten dplyrwerden

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

Zum Ausschließen bestimmter Spalten group_by_at(vars(-var1, -var2))können stattdessen die Daten gruppiert werden.

Wenn die Zeilenindizes und nicht nur die Daten tatsächlich benötigt werden, können Sie sie zuerst wie folgt hinzufügen:

df %>% add_rownames %>% group_by_at(vars(-rowname)) %>% filter(n()>1) %>% pull(rowname)
Holger Brandl
quelle
1
Gute Verwendung von n(). Vergessen Sie nicht, die Gruppierung des resultierenden Datenrahmens aufzuheben.
qwr
@qwr Ich habe die Antwort angepasst, um die Gruppierung des Ergebnisses aufzuheben
Holger Brandl
2

Hier ist die Lösung von @Joshua Ulrich als Funktion. Mit diesem Format können Sie diesen Code auf dieselbe Weise verwenden, wie Sie duplicated () verwenden würden:

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

Verwenden Sie das gleiche Beispiel:

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

Wenn Sie daran interessiert sind, welche Zeilen für bestimmte Spalten dupliziert werden, können Sie einen Plyr- Ansatz verwenden:

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

Hinzufügen einer Zählvariablen mit dplyr :

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

Für doppelte Zeilen (unter Berücksichtigung aller Spalten):

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

Der Vorteil dieser Ansätze besteht darin, dass Sie angeben können, wie viele Duplikate als Cutoff verwendet werden sollen.

qwr
quelle
0

Ich hatte ein ähnliches Problem, musste jedoch doppelte Zeilen anhand von Werten in bestimmten Spalten identifizieren. Ich habe die folgende dplyr- Lösung gefunden:

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

Der Code gruppiert die Zeilen nach bestimmten Spalten. Wenn die Länge einer Gruppe größer als 1 ist, markiert der Code alle Zeilen in der Gruppe als dupliziert. Sobald dies erledigt ist, können Sie die DuplicatedSpalte zum Filtern usw. verwenden.

Adnan Hajizada
quelle