2017-05-30 2 views
2

Ich habe eine große Anzahl von Strings (~ 280.000), die alle das folgende Format "ABC12D/XYZ34A" haben. In meinen Daten hat jede dieser Zeichenfolgen einen doppelten Eintrag, der identisch ist, aber umgekehrt, z. "XYZ34A/ABC12D" für das obige Beispiel. So sieht meine Daten etwas wie folgt aus:Effiziente Suche nach umgekehrten Strings in R

1 "ABC12D/XYZ34A" 
2 "TUR44F/SWP29R" 
3 "PLL93S/WQQ22F" 
4 "YNV77C/AAZ05S" 
5 "SWP29R/TUR44F" 
6 "AAZ05S/YNV77C" 
7 "CLK86G/ERF74Q" 
8 "XYZ34A/ABC12D" 
9 "ERF74Q/CLK86G" 
10 "WQQ22F/PLL93S" 

Row 1 Treffer Reihe 8, Reihe 2 Streichhölzer Reihe 5 usw.

Meine Ziele sind: 1) für eine bestimmte Zeichenfolge, wo seine umgekehrt Eintrag diesen Index wird und halten und dann 2) die Rückbuchung mit dem nicht umgekehrten Eintrag ersetzen:

1 "ABC12D/XYZ34A" 8 
2 "TUR44F/SWP29R" 5 
3 "PLL93S/WQQ22F" 10 
4 "YNV77C/AAZ05S" 6 
5 "TUR44F/SWP29R" 0 
6 "YNV77C/AAZ05S" 0 
7 "CLK86G/ERF74Q" 9 
8 "ABC12D/XYZ34A" 0 
9 "CLK86G/ERF74Q" 0 
10 "PLL93S/WQQ22F" 0 

Derzeit ich tue dies in der folgenden Art und Weise mit einer Schleife:

df <- data.frame(c("ABC12D/XYZ34A", "TUR44F/SWP29R", "PLL93S/WQQ22F", 
"YNV77C/AAZ05S", "SWP29R/TUR44F", "AAZ05S/YNV77C", "CLK86G/ERF74Q", 
"XYZ34A/ABC12D", "ERF74Q/CLK86G", "WQQ22F/PLL93S"), stringsAsFactors = 
FALSE) 

colnames(df) <- "entries" 
df 

# Reverse function 
reverse.entry <- function(string) { 
    string.reversed <- paste(rev(strsplit(string, "/")[[1]]), collapse = '/') 
    string.reversed 
} 

duplicate.flag <- list() 
duplicate.idx <- list() 

# Find and replace reversed entries 
for (i in 1:dim(df)[[1]]) { 
    # current entry 
    string = df[i,] 

    # reverse the current entry 
    string.reversed <- reverse.entry(string) 

    # if any other entry matches the reversed string get match index 
    if (grepl(string.reversed, df)) { 

    print(sprintf("%d found a reversal", i)) 
    idx <- which(df == string.reversed) 
    duplicate.flag[i] <- 1; 
    duplicate.idx[i] <- idx; 
    # replace reversed strings with original strings 
    df[idx,] <- string 
    } else { 
    duplicate.flag[i] <- 0; 
    duplicate.idx[i] <- 0; 
    } 

} 

data.frame(df, unlist(duplicate.idx), unlist(duplicate.flag)) 

Dies ist jedoch ziemlich langsam und dauert mehrere Stunden. Gibt es eine bessere Möglichkeit, dies zu programmieren? Ich bin ziemlich neu in R und Programmierung, also bin ich nicht besonders gut in der Vektorisierung usw. Da jeder Eintrag einen umgekehrten Eintrag hat, könnte ich auch einfach die Schleife für 1: dim (df) [[1]]/2 haben Schon viel Zeit sparen?

Vielen Dank!

+1

Gibt es eine Regel zu identifizieren, die das Original ist und wer das Gegenteil? Kommt das Original im Datenrahmen an erster Stelle? – Lamia

+0

Keine harte Regel und es spielt keine Rolle. Ich behandle das, das zuerst als das Original kommt, aber solange es am Ende übereinstimmt, ist es egal, welches man verändert hat. – KarenKoltrane

Antwort

1

Sie so etwas tun könnte ...

df$no <- seq_along(df$entries) #number the entries 
df$rev <- gsub("(.+)/(.+)","\\2/\\1",df$entries) #calculate reverse entries 
df$whererev <- match(df$rev, df$entries) #identify where reversed entries occur 
df$whererev[df$whererev>df$no] <- NA #remove the first of each duplicated pair 
df$entries[!is.na(df$whererev)] <- df$rev[!is.na(df$whererev)] #replace duplicates 

df 
    no  entries   rev whererev 
1 1 ABC12D/XYZ34A XYZ34A/ABC12D  NA 
2 2 TUR44F/SWP29R SWP29R/TUR44F  NA 
3 3 PLL93S/WQQ22F WQQ22F/PLL93S  NA 
4 4 YNV77C/AAZ05S AAZ05S/YNV77C  NA 
5 5 TUR44F/SWP29R TUR44F/SWP29R  2 
6 6 YNV77C/AAZ05S YNV77C/AAZ05S  4 
7 7 CLK86G/ERF74Q ERF74Q/CLK86G  NA 
8 8 ABC12D/XYZ34A ABC12D/XYZ34A  1 
9 9 CLK86G/ERF74Q CLK86G/ERF74Q  7 
10 10 PLL93S/WQQ22F PLL93S/WQQ22F  3 

Bitte beachte, dass ich das zweite Duplikat markiert haben eher als die erste, da dies es einfacher (und wahrscheinlich wesentlich schneller) macht die zweite zu ersetzen, anstatt von der ersten nachsehen zu müssen. (Zeile 4 hätte < statt >, wenn Sie Ihre Markierung des ersten jedes duplizierten Paares neu erstellen möchten).

+0

großartige Lösung! Wird der 'sapply()' Schritt benötigt? Ich denke 'df $ woerev <- match (df $ rev, df $ entries)' gibt das gleiche Ergebnis und ist fast 3x so schnell. –

+1

Ja, du hast Recht, das ist besser. Ich werde die Lösung aktualisieren. Danke vielmals! –

+1

Der String nicht umkehrt, nur ein Swap der beiden Elemente auf beiden Seiten der /. –

0

Hier ist meine Lösung:

require(data.table) 
get_index <- function(string,values,current_index){ 
    string_present <- match(string,values) 
    string_present[string_present<current_index] <- 0 
    return(string_present) 
} 

mydata <- c("ABC12D/XYZ34A","TUR44F/SWP29R","PLL93S/WQQ22F","YNV77C/AAZ05S","SWP29R/TUR44F","AAZ05S/YNV77C","CLK86G/ERF74Q","XYZ34A/ABC12D","ERF74Q/CLK86G","WQQ22F/PLL93S") 
mydf <- data.table(mystring = mydata,stringsAsFactors = FALSE) 
mydf[,revmystring:=gsub("(.+)\\/(.+)","\\2\\/\\1",mystring)] 
mydf[,duplicate_index:=get_index(revmystring,mystring,.I)] 

Die Lösung es gibt, ist:

> mydf 
     mystring revmystring duplicate_index 
1: ABC12D/XYZ34A XYZ34A/ABC12D    8 
2: TUR44F/SWP29R SWP29R/TUR44F    5 
3: PLL93S/WQQ22F WQQ22F/PLL93S    10 
4: YNV77C/AAZ05S AAZ05S/YNV77C    6 
5: SWP29R/TUR44F TUR44F/SWP29R    0 
6: AAZ05S/YNV77C YNV77C/AAZ05S    0 
7: CLK86G/ERF74Q ERF74Q/CLK86G    9 
8: XYZ34A/ABC12D ABC12D/XYZ34A    0 
9: ERF74Q/CLK86G CLK86G/ERF74Q    0 
10: WQQ22F/PLL93S PLL93S/WQQ22F    0 

Sie können dies auch ohne data.table implementieren.

+0

Das funktioniert gut, um mir den doppelten Index zu geben, ersetzt aber nicht den umgekehrten Originaleintrag. Addiert man diese Linie hat es aber: 'mydf $ mystring [mydf $ duplicate_index] <-mydf $ mystring [mydf $ duplicate_index> 0]' – KarenKoltrane

0

Hier ist ein propostion mit outer und gsub:

## Create a matrix of correspondence o between elements and reverses 
o = outer(df[,1],df[,1],function(x,y) gsub("(.*)/(.*)","\\2/\\1",y)==x) 
o[upper.tri(o)] = F 
## Identify the indices of correspondence 
df$ind = unlist(apply(o,2,function(x) which(x==T)[1])) 
df$ind[is.na(df$ind)] = 0 
## Replace reverses by originals 
df[,1][df$ind[df$ind!=0]] = df[,1][df$ind!=0] 

Das gibt:

 V1  ind 
1 ABC12D/XYZ34A 8 
2 TUR44F/SWP29R 5 
3 PLL93S/WQQ22F 10 
4 YNV77C/AAZ05S 6 
5 TUR44F/SWP29R 0 
6 YNV77C/AAZ05S 0 
7 CLK86G/ERF74Q 9 
8 ABC12D/XYZ34A 0 
9 CLK86G/ERF74Q 0 
10 PLL93S/WQQ22F 0 
Verwandte Themen