Estoy diseñando un complemento para identificar de forma única el contenido en varias páginas web, según las direcciones.
Entonces puedo tener una dirección que se parece a:
1 someawesome street, anytown, F100 211
más tarde puedo encontrar esta dirección en un formato ligeramente diferente.
1 someawesome street, F100 211,
o tal vez tan vago como
someawesome street F100
Estas son técnicamente la misma dirección, pero con un nivel de similitud. Me gustaría a) generar un identificador único para cada dirección para realizar búsquedas, yb) averiguar cuándo aparece una dirección muy similar.
¿Qué algoritmos / técnicas / métricas de cadena debo mirar? La distancia de Levenshtein parece una opción obvia, pero es curioso si hay otros enfoques que se presten aquí.
algorithms
string-matching
Squiggs
fuente
fuente
Respuestas:
El algoritmo de Levenstein se basa en el número de inserciones, eliminaciones y sustituciones en cadenas.
Desafortunadamente, no tiene en cuenta un error ortográfico común, que es la transposición de 2 caracteres (por ejemplo, someawesome vs someaewsome). Entonces preferiría el algoritmo Damerau-Levenstein más robusto .
No creo que sea una buena idea aplicar la distancia en cadenas enteras porque el tiempo aumenta abruptamente con la longitud de las cadenas comparadas. Pero aún peor, cuando se eliminan componentes de dirección, como ZIP, direcciones completamente diferentes pueden coincidir mejor (medido usando la calculadora de Levenshtein en línea ):
Estos efectos tienden a empeorar para nombres de calles más cortos.
Así que será mejor que uses algoritmos más inteligentes. Por ejemplo, Arthur Ratz publicó en CodeProject un algoritmo para la comparación de texto inteligente. El algoritmo no imprime una distancia (ciertamente puede enriquecerse en consecuencia), pero identifica algunas cosas difíciles como mover bloques de texto (por ejemplo, el intercambio entre la ciudad y la calle entre mi primer ejemplo y mi último ejemplo).
Si dicho algoritmo es demasiado general para su caso, entonces debería realmente trabajar por componentes y comparar solo componentes comparables. Esto no es algo fácil si desea analizar cualquier formato de dirección en el mundo. Pero si el objetivo es más específico, por ejemplo, es ciertamente factible. Por ejemplo, "street", "st.", "Place", "plazza" y sus errores ortográficos habituales podrían revelar la parte de la calle de la dirección, cuya parte principal sería, en principio, el número. El código postal ayudaría a localizar la ciudad, o alternativamente es probablemente el último elemento de la dirección, o si no le gusta adivinar, puede buscar una lista de nombres de ciudades (por ejemplo, descargar una base de datos de código postal gratuita). Luego puede aplicar Damerau-Levenshtein solo en los componentes relevantes.
fuente
La distancia de Levenshtein es mejor para las palabras.
Si las palabras se escriben (principalmente) correctamente, mire la bolsa de palabras . Puede parecer una muerte excesiva, pero TF-IDF y la similitud del coseno .
O podrías usar Lucene gratis. Creo que hacen similitud coseno.
fuente
En primer lugar, tendrías que analizar las direcciones de la página web, RegEx es uno que debes tomar, sin embargo, puede ser muy difícil analizar direcciones usando RegEx. Probablemente termines teniendo que revisar una lista de posibles formatos de direccionamiento y una o más expresiones geniales que coincidan. No estoy muy familiarizado con el análisis de direcciones, pero recomendaría echar un vistazo a esta pregunta que sigue una línea de pensamiento similar: Analizador de direcciones generales para texto de forma libre.
La distancia de Levenshtein es útil, pero solo después de separar la dirección en sus partes. Considere las siguientes direcciones.
123 someawesome st.
y124 someawesome st.
Estas direcciones son ubicaciones totalmente diferentes, pero su distancia de Levenshtein es de solo 1. Esto también se puede aplicar a algo así8th st.
y9th st.
los nombres de calles similares no suelen aparecer en la misma página web, pero no es desconocida. La página web de una escuela puede tener la dirección de la biblioteca al otro lado de la calle, por ejemplo, o la iglesia a pocas cuadras. Esto significa que los únicos datos que la distancia de Levenshtein es fácilmente utilizable es la distancia entre 2 puntos de datos, como la distancia entre la calle y la ciudad.En cuanto a descubrir cómo separar los diferentes campos, es bastante simple una vez que obtenemos las direcciones. Afortunadamente, la mayoría de las direcciones vienen en formatos muy específicos, con un poco de magia RegEx debería ser posible separarlas en diferentes campos de datos. Incluso si la dirección no está bien formateada, todavía hay alguna esperanza. Las direcciones siempre (casi) siguen el orden de magnitud. Su dirección debe estar en algún lugar de una cuadrícula lineal como esta, dependiendo de la cantidad de información que se proporcione y de qué se trata:
StreetNumber < Street < City < State < Country
Ocurre raramente, si es que la dirección salta de un campo a otro no adyacente. No va a ver una calle, luego país, o número de calle, luego ciudad, muy a menudo.
fuente
Pregunta acerca de los algoritmos de similitud de cadenas pero sus cadenas son direcciones. Enviaría las direcciones a una API de ubicación como Google Place Search y las usaría
formatted_address
como punto de comparación. Ese parece ser el enfoque más preciso.Para las cadenas de direcciones que no pueden ubicarse a través de una API, puede recurrir a algoritmos de similitud.
fuente
Un algoritmo genial que es útil pero requiere una base de datos preestablecida de respuestas anteriores se llama: Distancia de edición de línea.
La distancia de edición de línea, como función, puede devolver un "cuán diferentes son esas dos palabras".
Una palabra como "dogma" y "perro", obtendrá un valor de 3 (por 3 caracteres adicionales).
O "gato" y "sombrero", recupera un valor de 1 (para un personaje diferente).
(Fuente: https://en.wikipedia.org/wiki/Edit_distance )
fuente
De hecho, usar alguna función de distancia parece un buen enfoque. Pero el problema es encontrar la cadena más cercana de una dirección dada, lo que está lejos de ser trivial.
Estás describiendo una amplia categoría de algoritmos aquí. Echa un vistazo a la búsqueda de vecinos más cercanos
Como se menciona en un comentario, si encuentra una manera de separar los componentes de la dirección (nombre de la calle, número, etc.), la tarea será mucho más fácil.
fuente
LongestCommonSubsequence (de Apache commons-text) puede ser otro enfoque para probar con direcciones. Si define la similitud de dos como la proporción de " longitud de subsecuencia común / máx. (Longitudes de dirección) ", puede aplicar un umbral de tolerancia, por ejemplo, 0.8 que definirá coincidencia / no coincidencia. De esta forma le permitirá hacer coincidir direcciones como " 1 someawesome st., Anytown " y " 1 someawesome street., Anytown ".
No es un algoritmo súper rápido, por lo que es posible que desee aplicar una recuperación rápida para minimizar las comparaciones. El ejemplo sería: evite la comparación si los códigos postales no coinciden o si la secuencia de solo dígitos extraídos es diferente.
fuente