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.
algorithms
string-matching
Squiggs.
fonte
fonte
Respostas:
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 ):
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.
fonte
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.
fonte
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.
e124 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 como8th st.
e9th 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.
fonte
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_address
como 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.
fonte
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 )
fonte
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.
fonte
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.
fonte