R - การขุดข้อความบนหลายคอลัมน์ด้วยระยะทางเลเวนชไทน์

ฉันต้องการเปรียบเทียบสตริงข้อความหลายครั้งในหลายคอลัมน์ผ่านระยะทางเลเวนชไทน์ (ฟังก์ชัน adist ใน R) สิ่งที่ฉันต้องการทำคือเปรียบเทียบ source1$name กับ source2$name หากไม่มีรายการที่ตรงกัน (เช่น หากส่งคืน NA สำหรับ match.s1.s2$s2.i ให้ดำเนินการฟังก์ชันเดียวกันโดยใช้ที่อยู่ (source1$address และ source2$address) ที่แสดงอยู่ในกรอบข้อมูลทั้งสอง โดยพื้นฐานแล้ว ฉันกำลังมองหาวิธีปรับแต่งการจับคู่ของฉันในหลายฟิลด์ ตัวอย่าง อยู่ด้านล่าง

name <- c("holiday inn", "geico", "zgf", "morton phillips")
address <- c("400 lafayette pl tupelo ms", "227 geico plaza chevy chase md", 
         "811 quincy st washington dc", "1911 1st st rockville md")

source1 <- data.frame(name, address)

name <- c("williams sonoma", "mamas bbq", "davis polk", "hop a long diner",
      "joes crag shack", "mike lowry place", "holiday inn", "zummer")

name2 <- c(NA, NA, NA, NA, NA, NA, "hi express", "zummer gunsul frasca")
address <- c("2 reads way new castle de", "248 w 4th st newark de",
         "1100 21st st nw washington dc", "1804 w 5th st wilmington de",
         "1208 kenwood parkway holdridge nb", "4203 ocean drive miami fl",
         "400 lafayette pl tupelo ms", "811 quincy st washington dc")
source2 <- data.frame(name, name2, address)

removeSPE <- function(x) gsub("[[:punct:]]", " ", x)

cleanup <- function(x){
x <- as.character(x) # convert to character
x <- tolower(x) # make all lowercase
x <- sapply(x, removeSPE) # remove special characters
x <- trimws(x) # remove extra white space
#x <- sapply(x, removeStopWords) # remove stopwords, defined above
#x <- trimws(x) # since stopwords have been removed, there is extra white space left, this removes it
x <- gsub("^. .$", "", x)
return(x)
}

source1$name <- cleanup(source1$name)
source2$name <- cleanup(source2$name)
source2$name2 <- cleanup(source2$name2)

source1$address <- cleanup(source1$address)
source2$address <- cleanup(source2$address)

source1$name <- cleanup(source1$name)
source2$name <- cleanup(source2$name)
source2$name2 <- cleanup(source2$name2)

dist.name<- adist(source1$name,source2$name, partial = TRUE, ignore.case = TRUE)
dist.name2 <- adist(source1$name, source2$name2, partial = TRUE, ignore.case = TRUE)
dist.address <- adist(source1$address, source2$address, partial = TRUE, ignore.case = TRUE)

min.name<-apply(dist.name, 2, min)
min.name2 <- apply(dist.name2, 2, min)


match.s1.s2<-NULL  
for(i in 1:nrow(dist.address))
{
s2.i<-match(min.name[i],dist.name[i,])
s1.i<-i
match.s1.s2<-
rbind(data.frame(s2.i=s2.i,s1.i=s1.i,s2name=source2[s2.i,]$name, s1name=source1[s1.i,]$name, 
                            adist=min.name[i], s1.i.address = source1[s1.i,]$address,
                            s2.i.address = source2[s2.i,]$address),match.s1.s2)
}

match.s1.s2

ผลลัพธ์ที่ต้องการคือแถว 3 ใน source1 ตรงกับแถว 8 ของ source2 และแถว 4 ของ source1 ตรงกับแถว 7 ของ source2 มีวิธีรวม dist.name2 และ dist.address (กำหนดไว้ด้านบน) ใน for-loop ข้างต้นหรือไม่ อาจเป็นคำสั่ง while? กรอบข้อมูลจริงที่ฉันจะใช้มีประมาณ 500 และ 24,000 แถว


person jvalenti    schedule 21.12.2017    source แหล่งที่มา


คำตอบ (1)


ระยะทางโคไซน์ดูเหมือนจะทำงานได้ค่อนข้างดี:

out_df <- c()
for(x in source1$name) {
  for(y in source2$full2) {
    if (is.na(source2[source2$full2 == y, "name2"])) {
      x2 <- source1[source1$name == x, "address"]
      y2 <- source2[source2$full2 == y, "address"]
      row <- data.frame(x, y2, stringdist(x, y, method="cosine", q = 1))
      names(row) <- c("name1", "full2", "distance")
      out_df <- rbind(out_df, row)
    } else {
      row <- data.frame(x, y, stringdist(x, y, method="cosine", q = 1))
      names(row) <- c("name1", "full2", "distance")
      out_df <- rbind(out_df, row)
    }
  }
}

names(out_df) <- c("name1", "full2", "distance")

grab <- aggregate(distance ~ name1, data = out_df, FUN = min)

merge(out_df, grab)

คุณยังคงต้องหาวิธียกเว้นผลลัพธ์ที่คุณไม่ต้องการ

person AidanGawronski    schedule 21.12.2017
comment
แล้วที่อยู่ล่ะ? - person jvalenti; 21.12.2017
comment
ฉันหมายถึงการใช้ระยะห่างระหว่างที่อยู่เป็นเกณฑ์การจับคู่หากมี NA สำหรับการจับคู่ชื่อ ดังนั้นหากการจับคู่ชื่อไม่ส่งคืนการจับคู่ ให้ค้นหาการจับคู่ที่ใกล้เคียงกับที่อยู่มากที่สุด ดูเหมือนว่านี่จะเป็นการเพิ่มที่อยู่ลงในกรอบข้อมูล - person jvalenti; 21.12.2017
comment
ฉันแก้ไขบัญชีที่อยู่มานานแล้ว แต่ฉันเดาว่า SO ไม่ได้แจ้งให้คุณทราบ - person AidanGawronski; 31.01.2018