2012-05-16 8 views
6

Ich habe zwei DatensätzeZusammenführen von Daten mit teilweise Übereinstimmung in r

datf1 <- data.frame (name = c("regular", "kklmin", "notSo", "Jijoh", 
"Kish", "Lissp", "Kcn", "CCCa"), 
number1 = c(1, 8, 9, 2, 18, 25, 33, 8)) 
#----------- 
    name number1 
1 regular  1 
2 kklmin  8 
3 notSo  9 
4 Jijoh  2 
5 Kish  18 
6 Lissp  25 
7  Kcn  33 
8 CCCa  8 

datf2 <- data.frame (name = c("reGulr", "ntSo", "Jijoh", "sean", "LiSsp", 
"KcN", "CaPN"), 
    number2 = c(2, 8, 12, 13, 20, 18, 13)) 
#------------- 
    name number2 
1 reGulr  2 
2 ntSo  8 
3 Jijoh  12 
4 sean  13 
5 LiSsp  20 
6 KcN  18 
7 CaPN  13 

ich sie mit Namen Spalt zusammenführen mag, jedoch mit teilweise Übereinstimmung (erlaubt ist, zu vermeiden, Rechtschreibfehler in großem Datensatz zu behindern Zusammenführung und sogar erfassen solche Rechtschreibfehler) und beispielsweise

(1) wenn in Folge vier Buchstaben (all, wenn die Anzahl von Buchstaben weniger als 4) an jeder Position - übereinstimmen, die

ABBCD = BBCDK = aBBCD = ramABBBCD = ABB 

(2) Fall fein sen Sititivität ist in der Übereinstimmung aus. Beispiel: ABBCD = aBbCd

(3) Der neue Datensatz enthält beide Namen (Namen aus datf1 und datf2). Mit diesem Buchstaben können wir feststellen, ob die Übereinstimmung perfekt ist (kann eine separate Spalte mit wie vielen Buchstaben übereinstimmen)

Ist eine solche Zusammenführung möglich?

Edits:

datf1 <- data.frame (name = c("xxregular", "kklmin", "notSo", "Jijoh", 
      "Kish", "Lissp", "Kcn", "CCCa"), 
        number1 = c(1, 8, 9, 2, 18, 25, 33, 8)) 
datf2 <- data.frame (name = c("reGulr", "ntSo", "Jijoh", "sean", 
      "LiSsp", "KcN", "CaPN"), 
        number2 = c(2, 8, 12, 13, 20, 18, 13)) 


uglyMerge(datf1, datf2) 
     name1 name2 number1 number2 matches 
1 xxregular <NA>  1  NA  0 
2  kklmin <NA>  8  NA  0 
3  notSo <NA>  9  NA  0 
4  Jijoh Jijoh  2  12  5 
5  Kish <NA>  18  NA  0 
6  Lissp LiSsp  25  20  5 
7  Kcn KcN  33  18  3 
8  CCCa <NA>  8  NA  0 
9  <NA> reGulr  NA  2  0 
10  <NA> ntSo  NA  8  0 
11  <NA> sean  NA  13  0 
12  <NA> CaPN  NA  13  0 
+0

Versucht, einige Formatierungen zu beheben. Ich sehe, dass Sie eine Kopie von "uglyMerge" hinzugefügt haben, die aus der Antwort von @sgibb zu stammen scheint. Die fehlende Übereinstimmung von "xxregular" mit "reGulr" mag für Sie offensichtlich sein, aber Sie müssen es uns vielleicht erklären, da es Ihren Spezifikationen zu entsprechen scheint –

Antwort

7

Vielleicht eine einfache Lösung gibt es, aber ich keine finden kann.
IMHO müssen Sie diese Art der Zusammenführung für Ihre eigenen implementieren.
Bitte ein hässliches Beispiel finden Sie unten (es gibt eine Menge Platz für Verbesserungen ist):

uglyMerge <- function(df1, df2) { 

    ## lower all strings to allow case-insensitive comparison 
    lowerNames1 <- tolower(df1[, 1]); 
    lowerNames2 <- tolower(df2[, 1]); 

    ## split strings into single characters 
    names1 <- strsplit(lowerNames1, ""); 
    names2 <- strsplit(lowerNames2, ""); 

    ## create the final dataframe 
    mergedDf <- data.frame(name1=as.character(df1[,1]), name2=NA, 
         number1=df1[,2], number2=NA, matches=0, 
         stringsAsFactors=FALSE); 

    ## store names of dataframe2 (to remember which strings have no match) 
    toMerge <- df2[, 1]; 

    for (i in seq(along=names1)) { 
     for (j in seq(along=names2)) { 
      ## set minimal match to 4 or to string length 
      minMatch <- min(4, length(names2[[j]])); 

      ## find single matches 
      matches <- names1[[i]] %in% names2[[j]]; 

      ## look for consecutive matches 
      r <- rle(matches); 

      ## any matches found? 
      if (any(r$values)) { 
       ## find max consecutive match 
       possibleMatch <- r$value == TRUE; 
       maxPos <- which(which.max(r$length[possibleMatch]) & possibleMatch)[1]; 

       ## store max conscutive match length 
       maxMatch <- r$length[maxPos]; 

       ## to remove FALSE-POSITIVES (e.g. CCC and kcn) find 
       ## largest substring 
       start <- sum(r$length[0:(maxPos-1)]) + 1; 
       stop <- start + r$length[maxPos] - 1; 
       maxSubStr <- substr(lowerNames1[i], start, stop); 

       ## all matching criteria fulfilled 
       isConsecutiveMatch <- maxMatch >= minMatch && 
            grepl(pattern=maxSubStr, x=lowerNames2[j], fixed=TRUE) && 
            nchar(maxSubStr) > 0; 

       if (isConsecutiveMatch) { 
        ## merging 
        mergedDf[i, "matches"] <- maxMatch 
        mergedDf[i, "name2"] <- as.character(df2[j, 1]); 
        mergedDf[i, "number2"] <- df2[j, 2]; 

        ## don't append this row to mergedDf because already merged 
        toMerge[j] <- NA; 

        ## stop inner for loop here to avoid possible second match 
        break; 
       } 
      } 
     } 
    } 

    ## append not matched rows to mergedDf 
    toMerge <- which(df2[, 1] == toMerge); 
    df2 <- data.frame(name1=NA, name2=as.character(df2[toMerge, 1]), 
        number1=NA, number2=df2[toMerge, 2], matches=0, 
        stringsAsFactors=FALSE); 
    mergedDf <- rbind(mergedDf, df2); 

    return (mergedDf); 
} 

Ausgang:

> uglyMerge(datf1, datf2) 
    name1 name2 number1 number2 matches 
1 xxregular reGulr  1  2  5 
2  kklmin <NA>  8  NA  0 
3  notSo <NA>  9  NA  0 
4  Jijoh Jijoh  2  12  5 
5  Kish <NA>  18  NA  0 
6  Lissp LiSsp  25  20  5 
7  Kcn KcN  33  18  3 
8  CCCa <NA>  8  NA  0 
9  <NA> ntSo  NA  8  0 
10  <NA> sean  NA  13  0 
11  <NA> CaPN  NA  13  0 
+0

danke für die großartige Lösung. Es funktioniert gut mit dem Beispiel, das ich zur Verfügung gestellt habe. Aber ich muss vielleicht weiter zwicken, da es scheint, dass es nicht funktioniert, wenn es nicht die ersten vier aufeinanderfolgenden Buchstaben sind, sehe einfach meine Bearbeitungen, wo ich die Addition xxx vor regulär hinzugefügt habe, nicht übereinstimmen. Trotzdem wird es mir einen guten Start geben, danke !! – jon

+0

@hijo Entschuldigung, es gab ein paar Bugs in meiner Substring-Berechnung. Bitte benutze meine modifizierte Version. – sgibb

+0

Es könnte auch von Nutzen sein, einige [edit distance] (http://en.wikipedia.org/wiki/Levenshtein_distance) zu verwenden, um String-Matching durchzuführen. Es hat [Umsetzung] (http://stackoverflow.com/questions/3182091/fast-levenshtein-distance-in-r) in R. –

3

agrep wird Ihnen den Einstieg.

so etwas wie:

lapply(tolower(datf1$name), function(x) agrep(x, tolower(datf2$name))) 

dann können Sie die max.distance Parameter einstellen, bis Sie die entsprechende Menge an Anpassungs erhalten. dann fusioniere, wie du willst.

Verwandte Themen