doppelte Zeilen in r identifizieren und markieren

11

Ich möchte doppelte Zeilen anhand von 2 Spalten identifizieren und markieren. Ich möchte für jedes Duplikat eine eindeutige Kennung erstellen, damit ich nicht nur weiß, dass die Zeile ein Duplikat ist, sondern auch, mit welcher Zeile es sich um ein Duplikat handelt. Ich habe einen Datenrahmen, der wie folgt aussieht, mit einigen doppelten Elementpaaren (beim Anpassen und Sitzen) und anderen Paaren, die nicht dupliziert werden. Während die Elementpaare dupliziert werden, sind die darin enthaltenen Informationen eindeutig (z. B. hat eine Zeile einen Wert in Wert1 für 1 Zeile, nicht jedoch Wert2 und Wert 3, die zweite oder doppelte Zeile enthält nur Zahlen für Wert2 und Wert3 nicht Wert1)

aktueller Datenrahmen

     value1 value2 value3 fit   sit  
[1,] "1"    NA     NA     "it1" "it2"
[2,] NA     "3"    "2"    "it2" "it1"
[3,] "2"    "3"    "4"    "it3" "it4"
[4,] NA     NA     NA     "it4" "it3"
[5,] "5"    NA     NA     "it5" "it6"
[6,] NA     NA     "2"    "it6" "it5"
[7,] NA     "4"    NA     "it7" "it9"

Code zum Generieren eines Beispieldatenrahmens

value1<-c(1,NA,2,NA,5,NA,NA)
value2<-c(NA,3,3,NA,NA,NA, 4)
value3<-c(NA,2,4,NA,NA,2, NA)
fit<-c("it1","it2","it3","it4", "it5", "it6","it7")
sit<-c("it2","it1","it4","it3", "it6", "it5", "it9")
df.now<-cbind(value1,value2,value3, fit, sit)

Ich möchte es in einen Datenrahmen konvertieren, der so aussieht:

gewünschter Datenrahmen

     val1 val2 val3 it1   it2  
[1,] "1"  "3"  "2"  "it1" "it2"
[2,] "2"  "3"  "4"  "it3" "it4"
[3,] "5"  NA   "2"  "it5" "it6"
[4,] NA   "4"  NA   "it7" "it9"

Ich habe überlegt, die folgenden Schritte auszuführen: 1. Erstellen Sie neue Variablen mit fit und setzen Sie sich mit dem niedrigsten und dem höchsten Element zusammen, um doppelte Paare zu identifizieren. 2. Identifizieren Sie doppelte Elementpaare. 3. Verwenden Sie ifelse, um eindeutige Informationen auszuwählen und einzugeben.

Ich weiß, wie man die Schritte 1 und 3 ausführt, bin aber bei Schritt 2 festgefahren. Ich denke, ich muss nicht nur das TRUE / FALSE-Duplikat identifizieren, sondern möglicherweise eine Spalte mit einer eindeutigen Kennung für jedes Elementpaar wie dieses (dort) sind 2 zusätzliche Zeilen wegen meines Schrittes 1):

     value1 value2 value3 fit   sit   lit   hit    dup
[1,] "1"    NA     NA     "it1" "it2" "it1" "it2"   1
[2,] NA     "3"    "2"    "it2" "it1" "it1" "it2"   1
[3,] "2"    "3"    "4"    "it3" "it4" "it3" "it4"   2
[4,] NA     NA     NA     "it4" "it3" "it3" "it4"   2
[5,] "5"    NA     NA     "it5" "it6" "it5" "it6"   3
[6,] NA     NA     "2"    "it6" "it5" "it5" "it6"   3
[7,] NA     "4"    NA     "it7" "it9" "it7" "it9"   NA

Ich bin mir nicht sicher, wie ich das machen soll.

Ich bitte um Hilfe bei Schritt 2 oder es gibt einen besseren Weg, dies zu lösen als die von mir beschriebenen Schritte.

Heather Clark
quelle

Antworten:

6

Eine dplyrOption könnte sein:

df.now %>%
 group_by(pair = paste(pmax(fit, sit), pmin(fit, sit), sep = "_")) %>%
 summarise_at(vars(starts_with("value")), ~ ifelse(all(is.na(.)), 
                                                   NA,
                                                   first(na.omit(.))))

  pair    value1 value2 value3
  <chr>    <dbl>  <dbl>  <dbl>
1 it2_it1      1      3      2
2 it4_it3      2      3      4
3 it6_it5      5     NA      2
4 it9_it7     NA      4     NA

Und wenn Sie die Paare auch in einzelnen Spalten benötigen, können Sie mit dem Hinzufügen von tidyr:

df.now %>%
 group_by(pair = paste(pmax(fit, sit), pmin(fit, sit), sep = "_")) %>%
 summarise_at(vars(starts_with("value")), ~ ifelse(all(is.na(.)), 
                                                   NA,
                                                   first(na.omit(.)))) %>%
 separate(pair, into = c("fit", "hit"), sep = "_", remove = FALSE)

  pair    fit   hit   value1 value2 value3
  <chr>   <chr> <chr>  <dbl>  <dbl>  <dbl>
1 it2_it1 it2   it1        1      3      2
2 it4_it3 it4   it3        2      3      4
3 it6_it5 it6   it5        5     NA      2
4 it9_it7 it9   it7       NA      4     NA
tmfmnk
quelle
Vielen Dank! Das funktioniert gut. Ich schätze es, die Option zum Trennen der Elemente hinzuzufügen.
Heather Clark
3

Verwenden Sie !duplicated()nach sorting.

df.now[!duplicated(t(apply(df.now[, c("fit", "sit")], 1, sort))), ]
#       value1 value2 value3 fit   sit  
# [1,] "1"    NA     NA     "it1" "it2"
# [2,] "2"    "3"    "4"    "it3" "it4"
# [3,] "5"    NA     NA     "it5" "it6"
# [4,] NA     "4"    NA     "it7" "it9"
jay.sf
quelle
Danke, für die schnelle Antwort. Diese Lösung löscht jedoch Informationen, die ich behalten muss. Ich möchte die Informationen aus den 3 Wertespalten kombinieren, die sich in den 2 Zeilen derselben Elementpaare befinden. Lassen Sie mich wissen, wenn dies nicht klar ist
Heather Clark
2

Verwenden melt/dcastvondata.table

library(data.table)
dcast(melt(setDT(df.now)[, c('fit1', 'sit1') := .(pmin(fit, sit), 
    pmax(fit, sit))], measure = patterns("^value"), na.rm = TRUE),
     fit1 + sit1 ~ variable, value.var = 'value')
#   fit1 sit1 value1 value2 value3
#1:  it1  it2      1      3      2
#2:  it3  it4      2      3      4
#3:  it5  it6      5     NA      2
#4:  it7  it9     NA      4     NA

Daten

df.now <- data.frame(value1,value2,value3, fit, sit, stringsAsFactors = FALSE)
akrun
quelle
2

Eine weitere data.tableOption:

library(data.table)
as.data.table(df.now)[, lapply(.SD, function(x) first(x[!is.na(x)])), 
    .(it1=pmin(fit, sit), it2=pmax(fit, sit)), 
    .SDcols=value1:value3]

Ausgabe:

   it1 it2 value1 value2 value3
1: it1 it2      1      3      2
2: it3 it4      2      3      4
3: it5 it6      5   <NA>      2
4: it7 it9   <NA>      4   <NA>
chinsoon12
quelle
1

Hier ist mein Versuch, data.table zu verwenden. Ihre Daten werden aufgerufen mydf. Zuerst habe ich für jede Zeile sortiert fitund siteine neue Variable erstellt group. Dann habe ich für jede Gruppe Werte in den drei Wertespalten sortiert (dh Wert1, Wert2 und Wert3). Schließlich habe ich die erste Zeile für jede Gruppe extrahiert.

library(data.table)

mydt <- setDT(mydf)[, group := paste(sort(.SD), collapse = "_"),
                    .SD = c("fit", "sit"), by = 1:nrow(mydf)][,
                        c("value1", "value2", "value3") := lapply(.SD, sort),
                        .SDcols = value1:value3, by = group][, .SD[1], by = group]

mydt[]

#     group value1 value2 value3 fit sit
#1: it1_it2      1      3      2 it1 it2
#2: it3_it4      2      3      4 it3 it4
#3: it5_it6      5     NA      2 it5 it6
#4: it7_it9     NA      4     NA it7 it9

DATEN

mydf <- structure(list(value1 = c(1L, NA, 2L, NA, 5L, NA, NA), value2 = c(NA, 
3L, 3L, NA, NA, NA, 4L), value3 = c(NA, 2L, 4L, NA, NA, 2L, NA
), fit = c("it1", "it2", "it3", "it4", "it5", "it6", "it7"), 
sit = c("it2", "it1", "it4", "it3", "it6", "it5", "it9")), class = "data.frame", row.names = c(NA, 
-7L))
Jazzurro
quelle
1

Dies kann auch mit getan werden tidyr‚s pivot_longermit values_drop_na = TRUEkombiniert mit pivot_wider:

library(tidyverse)

mydf %>%
   mutate(it1 = pmin(fit, sit), it2 = pmax(fit, sit)) %>%
   pivot_longer(cols = starts_with("value"), values_drop_na = TRUE) %>%
   pivot_wider(id_cols = c("it1", "it2"))

#> # A tibble: 4 x 5
#>   it1   it2   value1 value2 value3
#>   <chr> <chr>  <int>  <int>  <int>
#> 1 it1   it2        1      3      2
#> 2 it3   it4        2      3      4
#> 3 it5   it6        5     NA      2
#> 4 it7   it9       NA      4     NA

Daten

mydf <- structure(list(value1 = c(1L, NA, 2L, NA, 5L, NA, NA), value2 = c(NA, 
3L, 3L, NA, NA, NA, 4L), value3 = c(NA, 2L, 4L, NA, NA, 2L, NA
), fit = c("it1", "it2", "it3", "it4", "it5", "it6", "it7"), 
sit = c("it2", "it1", "it4", "it3", "it6", "it5", "it9")), class = "data.frame", row.names = c(NA, 
-7L))
Joris Chau
quelle