2017-12-21 22 views
1

levenshtein 거리 (adist 함수는 R)를 통해 텍스트 문자열을 여러 열에서 여러 번 비교하고 싶습니다. 내가하고 싶은 것은 source1$namesource2$name을 비교하는 것입니다. 일치하는 항목이없는 경우 (즉, match.s1.s2$s2.i에 대해 NA이 반환되면 두 데이터 프레임에 나열된 주소 (source1$addresssource2$address)를 사용하여 동일한 기능을 수행합니다. 기본적으로 여러 필드에서 일치 항목을 구체화 할 방법을 찾고 있습니다. 이하이다.levenshtein 거리로 여러 열을 대상으로 한 R- 텍스트 마이닝

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 

원하는 결과가 source2 행 7 source2 행 8 source1 일치 행 4 source1 경기에서 해당 행 3이다. 거기에 통합하는 방법 dist.name2dist.address (상기 정의 된) 위의 for-loop? 아마도 while 문일 것인가? 내가 사용할 실제 데이터 프레임은 50 0 및 24,000 행.

답변

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) 

당신은 아직도 당신이 원하지 않는 결과를 제외하는 방법을 파악해야합니다.

+0

주소는 무엇입니까? – jvalenti

+1

@jvalenti 업데이트를 참조하십시오. – AidanGawronski

+0

이름 일치에 대해 NA가있는 경우 일치 기준으로 주소 사이의 거리를 사용했습니다. 따라서 일치하는 이름이 일치하는 항목을 반환하지 않으면 주소와 가장 일치하는 항목을 검색하십시오. 그것은 단지 데이터 프레임에 주소를 추가하는 것처럼 보입니다. – jvalenti