2017-05-08 6 views
1

Ich habe eine Liste von Adressen, die nicht perfekt formatiert sind. Die Mehrheit hat die gleiche Grundstruktur, aber etwa ein Fünftel wurde nicht korrekt eingegeben.Bearbeiten von Adressstrings durch fehlende Worte in R Zugabe

df1 24 enthält Adressen, die jeweils als eine einzelne Zeichenfolge. Mein Ziel ist es, die Adressen zu finden, an denen Wörter oder Zahlen fehlen, und sie in jede Zeichenfolge einzufügen, in der sie am wahrscheinlichsten sind.

Mein Ansatz war die Anzahl des jeweils eindeutige Wort zu zählen/Zahl in dem Datenrahmen ist. Wörter, die in 80% oder mehr der Zeilen vorkommen, werden als diejenigen identifiziert, die zu jeder Adresse hinzugefügt werden müssen. Alle fehlenden Wörter müssen in der "richtigen" Position hinzugefügt werden, basierend auf der Formatierung der Adressen, die alle Adressierungselemente enthalten.

Ich kann die Worte identifizieren, die hinzugefügt werden müssen, aber ich habe keine Möglichkeit des Hinzufügens der Wörter in jeder Zeichenfolge gefunden, wenn sie nicht vorhanden sind; noch habe ich einen Weg gefunden, um sicherzustellen, dass sie an der richtigen Stelle innerhalb der Zeichenfolge hinzugefügt werden. Dies ist weiter kompliziert, da in meinem realen Datensatz die Formatierung der Adresse über Bereiche hinweg nicht konstant ist, d. H. In diesem Beispiel sind die Gebäudenummer und der Straßenname die dritten und vierten Adresselemente. Manchmal werden sie die 1. und 2., 2. und 3. usw. sein. Also muss die Lösung, die ich zu entwickeln versuche, auch dynamisch sein.

Das ist mein Beispieldatensatz:

df1 <- data.frame(V1=c("apt 23 5 roadname cityville b11abc", "apt 47 5 roadname cityville b11abc", "apt 24 roadname cityville b11abc", "apt 3 roadname cityville b11abc", "apt 44 5 roadname cityville b11abc", "apt 88 5 roadname cityville b11abc", "apt 7 5 roadname cityville b11abc", "apt 41 5 roadname cityville b11abc", "apt 55 5 roadname cityville b11abc", "apt 19 5 roadname cityville b11abc", "85 5 roadname cityville b11abc", "apt 12 roadname cityville b11abc", "apt 452 5 roadname cityville b11abc", "apt 1 5 roadname cityville b11abc", "99 5 roadname cityville b11abc", "apt 73 5 roadname cityville b11abc", "74 roadname cityville b11abc", "apt 75 5 roadname cityville b11abc", "apt 63 5 roadname cityville b11abc", "apt 48 5 roadname cityville b11abc", "apt 123 5 roadname cityville b11abc", "apt 56 5 roadname cityville b11abc", "6 5 roadname cityville b11abc", "apt 2 6 roadname cityville b11abc"), stringsAsFactors = F) 

Das ist meine Methode ist es, die Worte für die Identifizierung, die hinzugefügt werden müssen:

df2 <- data.frame(V1=c("apt 23 5 roadname cityville b11abc", "apt 47 5 roadname cityville b11abc", "apt 24 5 roadname cityville b11abc", "apt 3 5 roadname cityville b11abc", "apt 44 5 roadname cityville b11abc", "apt 88 5 roadname cityville b11abc", "apt 7 5 roadname cityville b11abc", "apt 41 5 roadname cityville b11abc", "apt 55 5 roadname cityville b11abc", "apt 19 5 roadname cityville b11abc", "apt 85 5 roadname cityville b11abc", "apt 12 5 roadname cityville b11abc", "apt 452 5 roadname cityville b11abc", "apt 1 5 roadname cityville b11abc", "apt 99 5 roadname cityville b11abc", "apt 73 5 roadname cityville b11abc", "apt 74 5 roadname cityville b11abc", "apt 75 5 roadname cityville b11abc", "apt 63 5 roadname cityville b11abc", "apt 48 5 roadname cityville b11abc", "apt 123 5 roadname cityville b11abc", "apt 56 5 roadname cityville b11abc", "apt 6 5 roadname cityville b11abc", "apt 2 6 roadname cityville b11abc"), stringsAsFactors = F) 
:

df1_words <- as.data.frame(table(t(as.data.frame(as.list(unlist(strsplit(df1$V1, " "))))))) 
df1_words_80 <- subset(df1_words, Freq >= round(nrow(df1)/100*80)) 

Dies ist der Ausgang ich bin nach ist

bearbeiten Nach applyi ng ikops Lösung für ein reales Dataset Ich bin auf ein Problem gestoßen, als die Liste Adressen enthält, die sich in der Länge unterscheiden. Das Problem, das ich denke, ist, dass einige kurze Adressen (z. B. mit 5 Wörtern) versuchen, häufige Wörter, die normalerweise an den Positionen 6,7,8,9 usw. zu finden sind, in eine Zeichenfolge einzufügen, die unmöglich ist, wodurch ein Fehler erzeugt wird. Ich kann mir zwei Lösungen vorstellen, entweder rückwärts zählen statt vorwärts, oder, möglicherweise, die einfachere Option (und die, von der ich denke, dass sie für meine speziellen Bedürfnisse am besten funktioniert), ignoriere einfach Zeilen, die ungewöhnlich kurze Strings enthalten.

kann das Problem, das ich, wenn df3 mit ikop Lösung

df3 <- data.frame(V1=c("apt really long name 23 5 roadname cityville b11abc", "apt really long name 47 5 roadname cityville b11abc", "apt really long name 24 roadname cityville b11abc", "apt 3 roadname cityville b11abc", "apt really long name 44 5 roadname cityville b11abc", "apt really long name 88 5 roadname cityville b11abc", "apt really long name 7 5 roadname cityville b11abc", "apt really long name 41 5 roadname cityville b11abc", "apt really long name 55 5 roadname cityville b11abc", "apt really long name 19 5 roadname cityville b11abc", "85 5 roadname cityville b11abc", "apt really long name 12 roadname cityville b11abc", "apt really long name 452 5 roadname cityville b11abc", "apt really long name 1 5 roadname cityville b11abc", "99 5 roadname cityville b11abc", "apt really long name 73 5 roadname cityville b11abc", "74 roadname cityville b11abc", "apt 75 5 roadname cityville b11abc", "apt really long name 63 5 roadname cityville b11abc", "apt really long name 48 5 roadname cityville b11abc", "apt really long name 123 5 roadname cityville b11abc", "apt really long name 56 5 roadname cityville b11abc", "6 5 roadname cityville b11abc", "apt really long name 2 6 roadname cityville b11abc"), stringsAsFactors = F) 

Antwort

1

Dies ist eine hacky-Lösung werden habe repliziert, dass Sie die meisten der Weg zu bekommen.

## For each word that appears in at least 80% of the rows compute 
## the most frequent position it appears in: 
library(dplyr) 
splitList <- strsplit(df1$V1, " ") 
wordVec <- unique(unlist(splitList)) 
wordFrequencyDf <- lapply(wordVec, function(theWord){ 
        freqWord <- sum(unlist(splitList) == theWord) 
        posVec <- unlist(lapply(splitList, function(x) which(x == theWord))) 
        mostFreqPos <- sort(table(posVec), decreasing = TRUE)[1] %>% names %>% as.numeric 
        data.frame(theWord, freqWord,mostFreqPos) 
       }) %>% 
     do.call('rbind',.) %>% 
     dplyr::mutate(theWord = as.character(theWord)) %>% 
     dplyr::filter(freqWord >= round(nrow(df1)*0.8)) %>% 
     dplyr::arrange(mostFreqPos) 

## Now loop over those words and insert the word in the relevant 
## position if necessary: 
for (ii in seq(along = wordFrequencyDf$theWord)){ 
    splitList <- lapply(splitList, function(x){ 
       relPos <- wordFrequencyDf$mostFreqPos[ii] 
       if (x[relPos] != wordFrequencyDf$theWord[ii]){ 
        if (relPos == 1){ 
         strBefore <- NULL      
        } else { 
         strBefore <- x[1:(relPos-1)] 
        }      
        if (relPos > length(x)){ 
         strAfter <- NULL       
        } else { 
         strAfter <- x[relPos:length(x)] 
        }     
        x <- c(strBefore, wordFrequencyDf$theWord[ii], strAfter) 
       } 
       x 
      }) 
} 

## Paste list together into a single string again: 
df2 <- data.frame(V1 = sapply(splitList, function(x) paste(x, collapse = " "))) 

Ergebnis:

df2 
#                V1 
# 1        apt 23 5 roadname cityville b11abc 
# 2        apt 47 5 roadname cityville b11abc 
# 3        apt 24 5 roadname cityville b11abc 
# 4        apt 3 5 roadname cityville b11abc 
# 5        apt 44 5 roadname cityville b11abc 
# 6        apt 88 5 roadname cityville b11abc 
# 7        apt 7 5 roadname cityville b11abc 
# 8        apt 41 5 roadname cityville b11abc 
# 9        apt 55 5 roadname cityville b11abc 
# 10       apt 19 5 roadname cityville b11abc 
# 11       apt 85 5 roadname cityville b11abc 
# 12       apt 12 5 roadname cityville b11abc 
# 13       apt 452 5 roadname cityville b11abc 
# 14        apt 1 5 roadname cityville b11abc 
# 15       apt 99 5 roadname cityville b11abc 
# 16       apt 73 5 roadname cityville b11abc 
# 17       apt 74 5 roadname cityville b11abc 
# 18       apt 75 5 roadname cityville b11abc 
# 19       apt 63 5 roadname cityville b11abc 
# 20       apt 48 5 roadname cityville b11abc 
# 21       apt 123 5 roadname cityville b11abc 
# 22       apt 56 5 roadname cityville b11abc 
# 23        apt 6 5 roadname cityville b11abc 
# 24 apt 2 5 roadname cityville b11abc 6 roadname cityville b11abc 

Sie können sehen, dass das Verfahren in der letzten Zeile fehlgeschlagen. Hier hatte die ursprüngliche Zeile keinen "5" an Position 3 (wie der Code erwartet). Aber das Problem ist, dass die Hausnummer nicht ganz fehlte, der String nur eine andere Hausnummer enthielt. Der Code, interpretierten jedoch dies als fehlende Gebäudenummer und eingefügt, um die "5" an Position 3.

+0

Sie hierfür sehr viel Dank.Ich habe es auf meinen realen Datensatz angewendet und es funktioniert fast immer. Es gibt jedoch ein Problem, wenn die Adressenliste Strings unterschiedlicher Länge enthält. Ich habe versucht, Ihre Lösung zu bearbeiten, um Zeilen zu ignorieren, die ungewöhnlich kurze Zeichenfolgen enthalten, aber ich habe nicht viel Glück. Ich habe ein Beispiel zu der Frage hinzugefügt, die den Fehler zeigt, den ich finde. – Chris