No R essa solução pode ser feita com o stringdist --> https://www.rdocumentation.org/packages/stringdist/versions/0.9.5.5/topics/stringdist
Eu geralmente inspeciono esses casos dessa forma:
# devtools::install_github("CenterForAssessment/randomNames")
library(randomNames)
library(dplyr)
library(stringdist)
# Gera mil nomes aleatórios
nomes_aleatorios <- randomNames(n = 1000, name.order = "first.last") %>%
# Para tirar a virgular que o randomNames coloca entre nome e sobrenome
gsub(", ", " ", .) %>%
# coloca tudo em caixa baixa
tolower() %>%
# remove os acentos
iconv(to="ASCII//TRANSLIT")
# Uma matriz de distâncias entre os nomes
dist_nomes <- stringdistmatrix(nomes_aleatorios, method = "dl") %>%
as.matrix()
# Coloca NA nas diagonais (já que é o nome comparado a si mesmo)
diag(dist_nomes) <- NA
# O index e o valor do nome mais próximo de cada nome
index_mais_proximo <- apply(dist_nomes, 1, which.min)
valor_mais_proximo <- apply(dist_nomes, 1, min, na.rm = TRUE)
# Gera uma tabela com o nome mais próximo de cada um e o valor e
# coloca uma flag se a distância é abaixo de um limiar
limiar <- 5
nomes_mais_prox <- data.frame(nome_1 = nomes_aleatorios,
nome_2 = nomes_aleatorios[index_mais_proximo],
dist = valor_mais_proximo) %>%
arrange(dist) %>%
mutate(flag = dist < limiar)
Aqui em uma função:
## x: Os nomes que se quer comparar
## return_logical: Se TRUE retorna um vetor lógico,
## se FALSE retorna um data frame com o par
## mais próximo e o quão próximo está.
## rm_accent: Se deve retirar os acentos antes de comparar
## ignore.case: Se deve ignorar maiúsculas e minúsculas
## treshold: Distância máxima para se considerar o nome
## parecido
## sd.method: método para se comparar os nomes
## sd.weight: pesos das penalidades (ver ?stringdist)
not_like <- function(x,
return_logical = TRUE,
rm_accent = TRUE,
ignore.case = TRUE,
treshold = 1,
sd.method = "dl",
sd.weight = c(d = 1, i = 1, s = 1, t = 1)){
x0 <- x
if(rm_accent){
x <- iconv(x, to = "ASCII//TRANSLIT")
}
if(ignore.case){
x <- tolower(x)
}
mtx_dist <- stringdistmatrix(x,
method = sd.method) %>%
as.matrix()
diag(mtx_dist) <- NA
min_dist <- apply(mtx_dist, 1, min, na.rm = TRUE)
if(return_logical){
return(min_dist < treshold)
}
min_index <- apply(mtx_dist, 1, which.min)
df <- data.frame(name_1 = x0,
name_2 = x0[min_index],
dist = min_dist,
not_like = min_dist < treshold)
return(df)
}
# Exemplo
nomes <- randomNames(n = 1000)
nomes_sim <- not_like(x = nomes, return_logical = FALSE)