Как измерить сходство между строками?
У меня есть куча имен, и я хочу получить уникальные имена. Однако из-за орфографических ошибок и несоответствий в данных имена могут быть записаны неправильно. Я ищу способ проверить вектор строк, если две из них similair.
Например:
pres <- c(" Obama, B.","Bush, G.W.","Obama, B.H.","Clinton, W.J.")
Я хочу найти это " Obama, B."
а также "Obama, B.H."
очень похожи Есть ли способ сделать это?
2 ответа
Это может быть сделано на основе, например, расстояния Левенштейна. Существует несколько реализаций этого в разных пакетах. Некоторые решения и пакеты можно найти в ответах на эти вопросы:
- agrep: возвращать только лучшие совпадения
- В R, как я могу заменить строку, которая содержит определенный шаблон, на другую строку?
- Быстрое расстояние Левенштейна в R?
Но чаще всего agrep
буду делать что хочешь
> sapply(pres,agrep,pres)
$` Obama, B.`
[1] 1 3
$`Bush, G.W.`
[1] 2
$`Obama, B.H.`
[1] 1 3
$`Clinton, W.J.`
[1] 4
Может быть agrep
это то, что вы хотите? Он ищет приблизительные совпадения, используя расстояние редактирования Левенштейна.
lapply(pres, agrep, pres, value = TRUE)
[[1]]
[1] " Obama, B." "Obama, B.H."
[[2]]
[1] "Bush, G.W."
[[3]]
[1] " Obama, B." "Obama, B.H."
[[4]]
[1] "Clinton, W.J."
Добавьте еще один дубликат, чтобы показать, что он работает с несколькими дубликатами.
pres <- c(" Obama, B.","Bush, G.W.","Obama, B.H.","Clinton, W.J.", "Bush, G.")
adist показывает расстояние между двумя символами
adist(" Obama, B.", pres)
# [,1] [,2] [,3] [,4] [,5]
# [1,] 0 9 3 10 7
Например, чтобы выбрать ближайшую строку к " Obama, B."
Вы можете взять тот, который имеет минимальное расстояние. Чтобы избежать идентичной строки, я взял только расстояния больше нуля:
d <- adist(" Obama, B.", pres)
pres[min(d[d>0])]
# [1] "Obama, B.H."
Чтобы получить уникальные имена с учетом орфографических ошибок и несоответствий, вы можете сравнить каждую строку со всеми предыдущими. Затем, если есть подобный, удалите его. Я создал keepunique()
функция, которая выполняет это. keepunique()
затем применяется ко всем элементам вектора последовательно с Reduce()
,
keepunique <- function(previousones, x){
if(any(adist(x, previousones)<5)){
x <- NULL
}
return(c(previousones, x))
}
Reduce(keepunique, pres)
# [1] " Obama, B." "Bush, G.W." "Clinton, W.J."