Estoy buscando un algoritmo de similitud de cadenas que produzca mejores resultados en cadenas de longitud variable que las que generalmente se sugieren (distancia levenshtein, índice sonoro, etc.).
Por ejemplo,
Dada la cadena A: "Robert",
Luego cadena B: "Amy Robertson"
sería una mejor combinación que
Cadena C: "Richard"
Además, preferiblemente, este algoritmo debe ser independiente del idioma (también funciona en otros idiomas además del inglés).
string-matching
ranking
similarity
fuzzy-search
marzagao
fuente
fuente
Respuestas:
Simon White de Catalysoft escribió un artículo sobre un algoritmo muy inteligente que compara pares de caracteres adyacentes que funciona realmente bien para mis propósitos:
http://www.catalysoft.com/articles/StrikeAMatch.html
Simon tiene una versión Java del algoritmo y a continuación escribí una versión PL / Ruby (tomada de la versión ruby simple hecha en el comentario de entrada del foro relacionado por Mark Wong-VanHaren) para que pueda usarla en mis consultas de PostgreSQL:
¡Funciona de maravilla!
fuente
string_similarity("vitamin B", "vitamin C") #=> 1
¿hay una manera fácil de prevenir este tipo de comportamiento?La respuesta de marzagao es genial. Lo convertí a C #, así que pensé en publicarlo aquí:
Enlace Pastebin
fuente
(2.0 * intersection) / union
: obtengo Double.NaN al comparar dos cadenas vacías.Aquí hay otra versión de la respuesta de marzagao , esta escrita en Python:
fuente
Aquí está mi implementación PHP del algoritmo StrikeAMatch sugerido, por Simon White. Las ventajas (como dice en el enlace) son:
Un verdadero reflejo de similitud léxica : las cadenas con pequeñas diferencias deben reconocerse como similares. En particular, una superposición de subcadenas significativa debe apuntar a un alto nivel de similitud entre las cadenas.
Una solidez a los cambios en el orden de las palabras : dos cadenas que contienen las mismas palabras, pero en un orden diferente, deben reconocerse como similares. Por otro lado, si una cadena es solo un anagrama aleatorio de los caracteres contenidos en la otra, entonces (generalmente) debería reconocerse como diferente.
Independencia del idioma : el algoritmo debería funcionar no solo en inglés, sino en muchos idiomas diferentes.
fuente
Una versión más corta de la respuesta de John Rutledge :
fuente
intersection
variable es un desperdicio de línea.Esta discusión ha sido realmente útil, gracias. Convertí el algoritmo a VBA para usarlo con Excel y escribí algunas versiones de una función de hoja de trabajo, una para la comparación simple de un par de cadenas y la otra para comparar una cadena con un rango / matriz de cadenas. La versión strSimLookup devuelve la última mejor coincidencia como una cadena, índice de matriz o métrica de similitud.
Esta implementación produce los mismos resultados enumerados en el ejemplo de Amazon en el sitio web de Simon White con algunas excepciones menores en los partidos de baja puntuación; No estoy seguro de dónde entra la diferencia, podría ser la función Split de VBA, pero no he investigado ya que funciona bien para mis propósitos.
fuente
Lo siento, la respuesta no fue inventada por el autor. Este es un algoritmo bien conocido que fue presentado por primera vez por Digital Equipment Corporation y a menudo se lo conoce como herpes zóster.
http://www.hpl.hp.com/techreports/Compaq-DEC/SRC-TN-1997-015.pdf
fuente
Traduje el algoritmo de Simon White a PL / pgSQL. Esta es mi contribución.
fuente
Las métricas de similitud de cadenas contienen una visión general de muchas métricas diferentes utilizadas en la comparación de cadenas ( Wikipedia también tiene una visión general). Gran parte de estas métricas se implementan en una biblioteca simétrica .
Otro ejemplo de métrica, no incluido en la descripción general dada es, por ejemplo, la distancia de compresión (intentando aproximar la complejidad de Kolmogorov ), que puede usarse para textos un poco más largos que el que usted presentó.
También puede considerar examinar un tema mucho más amplio del procesamiento del lenguaje natural . Estos paquetes R pueden ayudarlo a comenzar rápidamente (o al menos darle algunas ideas).
Y una última edición: busque las otras preguntas sobre este tema en SO, hay bastantes preguntas relacionadas.
fuente
Una versión PHP más rápida del algoritmo:
Para los datos que tenía (aproximadamente 2300 comparaciones), tuve un tiempo de ejecución de 0.58 segundos con la solución Igal Alkon versus 0.35 segundos con la mía.
fuente
Una versión en la bella Scala:
fuente
Aquí está la versión R:
fuente
Publicando la respuesta de marzagao en C99, inspirada en estos algoritmos
Algunas pruebas basadas en el artículo original :
fuente
Sobre la base de la increíble versión C # de Michael La Voie, según la solicitud para que sea un método de extensión, esto es lo que se me ocurrió. El principal beneficio de hacerlo de esta manera es que puede ordenar una lista genérica por el porcentaje de coincidencia. Por ejemplo, considere que tiene un campo de cadena llamado "Ciudad" en su objeto. Un usuario busca "Chester" y desea devolver los resultados en orden descendente de coincidencia. Por ejemplo, desea que aparezcan coincidencias literales de Chester antes de Rochester. Para hacer esto, agregue dos nuevas propiedades a su objeto:
Luego, en cada objeto, establezca SearchText en lo que el usuario buscó. Luego puede ordenarlo fácilmente con algo como:
Aquí está la ligera modificación para que sea un método de extensión:
fuente
Mi implementación de JavaScript toma una cadena o matriz de cadenas y un piso opcional (el piso predeterminado es 0.5). Si le pasa una cadena, devolverá verdadero o falso dependiendo de si el puntaje de similitud de la cadena es mayor o igual que el piso. Si le pasa un conjunto de cadenas, devolverá un conjunto de esas cadenas cuyo puntaje de similitud es mayor o igual al piso, ordenado por puntaje.
Ejemplos:
Aquí está:
fuente
for(var j = 0; j < pairs1.length; j++){
debería serfor(var j = 0; j < pairs2.length; j++){
El algoritmo del coeficiente Dice (respuesta de Simon White / marzagao) se implementa en Ruby en el método pair_distance_similar en la gema amatch
https://github.com/flori/amatch
Esta gema también contiene implementaciones de varios algoritmos de comparación aproximada y comparación de cadenas: distancia de edición de Levenshtein, distancia de edición de Sellers, distancia de Hamming, longitud de subsecuencia común más larga, longitud de subcadena común más larga, métrica de distancia de par, métrica de Jaro-Winkler .
fuente
Una versión de Haskell: siéntase libre de sugerir modificaciones porque no he hecho mucho Haskell.
fuente
Clojure:
fuente
¿Qué pasa con la distancia de Levenshtein, dividida por la longitud de la primera cadena (o alternativamente dividida mi longitud mínima / máxima / promedio de ambas cadenas)? Eso me ha funcionado hasta ahora.
fuente
Hola chicos, probé esto en javascript, pero soy nuevo en esto, ¿alguien sabe formas más rápidas de hacerlo?
fuente
x
yy
, y no debe recorrer los bucles con unfor..in..
bucle (usefor(..;..;..)
en su lugar).Aquí hay otra versión de Similitud basada en el índice Sørensen – Dice (respuesta de marzagao), esta escrita en C ++ 11:
fuente
Estaba buscando la implementación de puro rubí del algoritmo indicado por la respuesta de @marzagao. Desafortunadamente, el enlace indicado por @marzagao está roto. En la respuesta @ s01ipsist, indicó una coincidencia de gemas de rubí donde la implementación no está en rubí puro. Así que busqué un poco y encontré la gema fuzzy_match que tiene una implementación de rubí puro (aunque este uso de gemas
amatch
) aquí . Espero que esto ayude a alguien como yo.fuente