Qual algoritmo você usaria melhor para similaridade de string?

23

Estou projetando um plug-in para identificar exclusivamente o conteúdo em várias páginas da Web, com base em endereços.

Então, eu posso ter um endereço que se parece com:

1 someawesome street, anytown, F100 211

mais tarde, posso encontrar esse endereço em um formato ligeiramente diferente.

1 someawesome street, F100 211,

ou talvez tão vago quanto

someawesome street F100

Estes são tecnicamente o mesmo endereço, mas com um nível de similaridade. Eu gostaria de: a) gerar um identificador exclusivo para cada endereço para realizar pesquisas eb) descobrir quando um endereço muito semelhante aparecer.

Quais algoritmos / técnicas / métricas de string devo observar? A distância de Levenshtein parece ser uma escolha óbvia, mas curiosa se houver outras abordagens que se prestariam aqui.

Squiggs.
fonte
"Distância Levenshtein" não é um algoritmo.
gnasher729
A menos que você introduza uma análise básica, a distância bruta de Levenstein não será tão boa. Você deve tentar pelo menos identificar palavras que possam ser ruas, nomes de cidades etc. e aquelas que possam ser números de ruas ou códigos postais. Em seguida, talvez aplique Levenstein a esses itens com algum comparador estatístico difuso, alimentado por lugares reais / nomes de ruas. Não é uma coisa fácil :)
7
@gnasher: Mas uma função que calcula a distância de Levenshtein é um algoritmo. Sem essa função, a distância de Levenshtein é apenas uma curiosidade intelectual.
Robert Harvey
Encontrei uma explicação muito prática com exemplos aqui: comparação de algortihms . Em conclusão, eles recomendam usar a similaridade de Jaro-Winkler, pois o algoritmo de Levenstein depende do comprimento da string, portanto, não é útil comparar.
Sandra Meneses

Respostas:

14

O algoritmo de Levenstein é baseado no número de inserções, exclusões e substituições em seqüências de caracteres.

Infelizmente, ele não leva em consideração um erro de ortografia comum, que é a transposição de 2 caracteres (por exemplo, algo impressionante versus algo bom). Então, eu prefiro o algoritmo Damerau-Levenstein mais robusto .

Não acho que seja uma boa ideia aplicar a distância em cadeias inteiras porque o tempo aumenta abruptamente com o comprimento das cadeias comparadas. Pior ainda, quando componentes de endereço, como o ZIP, são removidos, endereços completamente diferentes podem corresponder melhor (medido usando a calculadora online da Levenshtein ):

1 someawesome street, anytown, F100 211       (reference) 
1 someawesome st.,anytown                     (difference of 15, same address)     
1 otherplaces street,anytown,F100211          (difference of 13, different ddress) 
1 sameawesome street, othertown, CA98200      (difference of 13, different ddress)
anytown, 1 someawesome street                 (28 different same address)
anytown, F100 211, 1 someawesome street       (37 different same address)

Esses efeitos tendem a piorar para um nome de rua mais curto.

Então é melhor você usar algoritmos mais inteligentes. Por exemplo, Arthur Ratz publicou no CodeProject um algoritmo para comparação inteligente de texto. O algoritmo não imprime uma distância (certamente pode ser enriquecido de acordo), mas identifica algumas coisas difíceis, como a movimentação de blocos de texto (por exemplo, a troca entre cidade e rua entre meu primeiro exemplo e meu último exemplo).

Se esse algoritmo for geral demais para o seu caso, você deverá realmente trabalhar com componentes e comparar apenas componentes comparáveis. Isso não é fácil se você deseja analisar qualquer formato de endereço no mundo. Mas se o objetivo é mais específico, por exemplo, nos EUA, é certamente viável. Por exemplo, "street", "st.", "Place", "plazza" e seus erros ortográficos comuns podem revelar a parte da rua do endereço, cuja parte principal seria, em princípio, o número. O CEP ajudaria a localizar a cidade ou, alternativamente, é provavelmente o último elemento do endereço ou, se você não gosta de adivinhar, pode procurar uma lista de nomes de cidades (por exemplo, baixar um banco de dados de códigos postais grátis). Em seguida, você pode aplicar o Damerau-Levenshtein apenas aos componentes relevantes.

Christophe
fonte
Que tal classificar as duas cadeias de comparação antes da comparação? Descobri que isso pode ajudar na transposição.
openwonk
2

Distância Levenshtein é melhor para palavras

Se as palavras são (principalmente) escritas corretamente, olhe para o conjunto de palavras . Eu posso parecer exagerado, mas TF-IDF e semelhança de cosseno .

Ou você pode usar o Lucene grátis. Eu acho que eles fazem semelhança de cosseno.

paparazzo
fonte
1

Em primeiro lugar, você precisaria analisar a página da Web em busca de endereços. O RegEx é um deles, mas pode ser muito difícil analisar endereços usando o RegEx. Provavelmente, você precisará passar por uma lista de possíveis formatos de endereçamento e uma ou mais expressões correspondentes a eles. Não estou muito familiarizado com a análise de endereços, mas recomendo examinar esta questão, que segue uma linha de pensamento semelhante: Analisador de Endereço Geral para Texto em Forma Livre.

A distância de Levenshtein é útil, mas somente depois de separar o endereço em partes. Considere os seguintes endereços. 123 someawesome st.e 124 someawesome st.Esses endereços são totalmente diferentes locais, mas sua distância Levenshtein é de apenas 1. Isso também pode ser aplicada a algo como 8th st.e 9th st.nomes de ruas similares normalmente não aparecem na mesma página da web, mas não é inédito. A página da escola de uma escola pode ter o endereço da biblioteca do outro lado da rua, por exemplo, ou a igreja a alguns quarteirões abaixo. Isso significa que os únicos dados pelos quais a distância de Levenshtein é facilmente utilizável são a distância entre dois pontos de dados, como a distância entre a rua e a cidade.

Quanto a descobrir como separar os diferentes campos, é bem simples quando obtemos os endereços. Felizmente, a maioria dos endereços vem em formatos muito específicos. Com um pouco de magia RegEx, é possível separá-los em diferentes campos de dados. Mesmo se o endereço não estiver bem formatado, ainda há alguma esperança. Os endereços sempre (quase) seguem a ordem de magnitude. Seu endereço deve estar em algum lugar em uma grade linear como esta, dependendo da quantidade de informações fornecidas e do que é:

StreetNumber < Street < City < State < Country

Isso acontece raramente, se o endereço pular de um campo para um não adjacente. Você não verá uma rua e um país ou um número de rua e uma cidade com muita frequência.

Ucenna
fonte
2
Exceto que os endereços das ruas não são regulares e não podem ser analisados ​​com segurança por expressões regulares. Eles certamente não podem ser identificados com precisão se forem incorporados apenas em texto livre. Obviamente, é possível escrever algumas expressões regulares diferentes para corresponder a diferentes formatos comuns, se você já sabe onde está olhando.
Inútil
@ Useless Isso é verdade. É factível em teoria, mas subestimei a quantidade de trabalho necessária para colocar nela. Especialmente quando existem opções potencialmente melhores disponíveis. Eu alterei minha resposta para refletir isso.
Ucenna
1

Você pergunta sobre algoritmos de similaridade de strings, mas suas strings são endereços. Eu enviava os endereços para uma API de localização, como a Pesquisa no Google Place, e usava o formatted_addresscomo um ponto de comparação. Essa parece ser a abordagem mais precisa.

Para cadeias de endereços que não podem ser localizadas por meio de uma API, você pode recorrer a algoritmos de similaridade.

Dan Wilson
fonte
1
+1 Terceirize para obter o poder de especialistas para fazer o trabalho por você. Não precisa ser o Google, pois existem alguns prestadores de serviços por aí. Não perca tempo fazendo isso, a menos que a correspondência de endereços seja o seu negócio principal.
LoztInSpace 12/09/18
0

Um algoritmo interessante que é útil, mas requer um banco de dados predefinido de respostas anteriores, é chamado: Distância de edição da linha.

A distância de edição de linha, como uma função, pode retornar "quão diferentes são essas duas palavras".

Com uma palavra como "dogma" e "cachorro", você receberá um valor de 3 (para 3 caracteres extras).

Ou "gato" e "chapéu", retorne o valor 1 (para um caractere diferente).

(Fonte: https://en.wikipedia.org/wiki/Edit_distance )

John Greene
fonte
2
Qual é a vantagem sobre Levensthtein mencionado pelo OP?
Christophe
-1

De fato, usar alguma função de distância parece ser uma boa abordagem. Mas o problema, então, é encontrar a string mais próxima de um determinado endereço, o que está longe de ser trivial.

Você está descrevendo uma ampla categoria de algoritmos aqui. Pesquisa de vizinhos mais próximos

Como mencionado em um comentário, se você encontrar uma maneira de separar os componentes do endereço (nome da rua, número, etc.), isso facilitará a tarefa.

kjaquier
fonte
-1

LongestCommonSubsequence (do Apache commons-text) pode ser outra abordagem para tentar endereços. Se você definir a similaridade de dois como proporção de " comprimento de subsequência comum / máx. (Comprimento do endereço) ", poderá aplicar o limite de tolerância - por exemplo, 0,8 que definirá correspondência / não correspondência. Dessa forma, você poderá corresponder endereços como " 1 someawesome st., Anytown " e " 1 someawesome street., Anytown ".

Não é um algoritmo super rápido, portanto, você pode aplicar failbacks rápidos para minimizar as comparações. O exemplo seria - evite a comparação se os códigos postais não corresponderem ou se a sequência de dígitos extraídos for diferente.

Altair7852
fonte