Нечеткое Сопоставление и замена строк в кадре данных с использованием пользовательского словаря - PullRequest
0 голосов
/ 26 января 2019

У меня есть этот фрейм данных с аналогами (строки с небольшими синтаксическими различиями)

 place1 <- c("pondichery ", "Pondichery", "Pondichéry", "Port-Louis", "Port Louis  ")
 place2 <- c("Lorent", "Pondichery", " Lorient", "port-louis", "Port Louis")
 place3 <- c("Loirent", "Pondchéry", "Brest", "Port Louis", "Nantes")

 places2clean <- data.frame(place1, place2, place3)

Вот мой пользовательский словарь

  dictionnary <- c("Pondichéry", "Lorient", "Port-Louis", "Nantes", "Brest")

  dictionnary <- data.frame(dictionnary)

Я хочу сопоставить и заменить все строки на основе собственного словаря.

Ожидаемые результаты:

    place1     place2     place3
 Pondichéry     Lorient    Lorient
 Pondichéry Pondichéry Pondichéry
 Pondichéry    Lorient      Brest
 Port-Louis Port-Louis Port Louis
 Port-Louis   Port-Louis     Nantes

Как я могу использовать строковое расстояние для сопоставления и замены по всему фрейму данных?

Ответы [ 2 ]

0 голосов
/ 26 января 2019

Следующее сначала вычисляет матрицы расстояний между каждым столбцом и словарем, а затем получает строки с меньшим расстоянием.

library(stringdist)

places2clean[] <- lapply(places2clean, trimws)

d <- lapply(places2clean, function(x) {
  sapply(dictionnary$dictionnary, function(y) stringdist(x, y))
})
res <- sapply(d, function(x){
  inx <- apply(x, 1, which.min)
  dictionnary$dictionnary[inx]
})

as.data.frame(res)
#      place1     place2     place3
#1 Pondichéry    Lorient    Lorient
#2 Pondichéry Pondichéry Pondichéry
#3 Pondichéry    Lorient      Brest
#4 Port-Louis Port-Louis Port-Louis
#5 Port-Louis Port-Louis     Nantes
0 голосов
/ 26 января 2019

Здесь может быть использована либо базовая функция R adist, либо функция stringdist::amatch.Нет смысла превращать ваш словарь в data.frame, поэтому у меня его нет.

Если вы хотите поэкспериментировать, вы можете использовать разные методы для пакета stringdist, хотя здесь по умолчанию работает отлично.Обратите внимание, что для обеих функций выбрано наилучшее совпадение, но если нет близкого совпадения (как определено параметром maxDist), то возвращается NA.

library(stringdist)
# Using stringdist package
clean_places <- function(places, dictionary, maxDist = 5) {
  dictionary[amatch(places, dictionary, maxDist = maxDist)]
}

# Using base R
clean_places2 <- function(places, dictionary, maxDist = 5) {
  sm <- adist(places, dictionary)
  sm[sm > maxDist] <- NA
  dictionary[apply(sm, 1, which.min)]
}

dictionary <- c("Pondichéry", "Lorient", "Port-Louis", "Nantes", "Brest")
place1 <- c("pondichery ", "Pondichery", "Pondichéry", "Port-Louis", "Port Louis  ")
place2 <- c("Lorent", "Pondichery", " Lorient", "port-louis", "Port Louis")
place3 <- c("Loirent", "Pondchéry", "Brest", "Port Louis", "Nantes")

clean_places(place1, dictionary)
# [1] "Pondichéry" "Pondichéry" "Pondichéry" "Port-Louis" "Port-Louis"
clean_places(place2, dictionary)
# [1] "Lorient"    "Pondichéry" "Lorient"    "Port-Louis" "Port-Louis"
clean_places(place3, dictionary)
# [1] "Lorient"    "Pondichéry" "Brest"      "Port-Louis" "Nantes"    

clean_places2(place1, dictionary)
# [1] "Pondichéry" "Pondichéry" "Pondichéry" "Port-Louis" "Port-Louis"
clean_places2(place2, dictionary)
# [1] "Lorient"    "Pondichéry" "Lorient"    "Port-Louis" "Port-Louis"
clean_places2(place3, dictionary)
# [1] "Lorient"    "Pondichéry" "Brest"      "Port-Louis" "Nantes"    
...