Coincidencias de cadenas de texto en Python 3

publicado por: Anonymous

Estimados, alguien conoce un método para encontrar coincidencias no exactas entre cadenas de texto?

Por ejemplo:

Tengo el siguiente texto “STATUS MSG PACK ACM L” (columna 1) y debería devolverme “PACK L” (columna 2).

Tengo 2 listas, una escrita por una persona que son textos más largos y otra que corresponde al mensaje a buscar que es el correcto.

Adjunto un ejemplo de las dos listas: la columna 1 se debe buscar en la columna 2, y arrojar el elemento de la columna 2 más asociado:

https://drive.google.com/file/d/0B11sJdX_AaJBd2lvWGszaFpXM2c/view?usp=sharing

solución

Para búsquedas difusas hay mútiples herramientas y métodos, pero usando Python de fabrica contamos ya, con la librería base difflib que nos permite obtener un ratio de semejanza entre cadenas. Por ejemplo:

from difflib import SequenceMatcher as SM

s1 = 'Hola Mundo'
s2 = 'Hola Mundo cruel'
print(SM(None, s1, s2).ratio())

s1 = 'Hola Mundo'
s2 = 'Hola Mundo!'
print(SM(None, s1, s2).ratio())
> 0.7692307692307693
> 0.9523809523809523

En este ejemplo medimos la semejanza de Hola Mundocon otras cadenas y vemos que lógicamente Hola Mundo! obtiene un ratio de semejanza mayor que Hola Mundo cruel. La idea entonces, sería recorrer una lista, y por cada elemento, verificar los ratios con respecto a los elemento de la segunda lista, el mayor será el más semejante. Algo así:

import difflib

lista1 = ["STATUS MSG PACK ACM L"]
lista2 = ["LOW LIMIT VALVE L",
          "LOW LIMIT VALVE R",
          "PACK ACM L",
          "PACK ACM R",
          "PACK L",
          "PACK MODE L",]

d = difflib.Differ()

for search in lista1:
  matches = sorted(lista2, key=lambda x: difflib.SequenceMatcher(None, x, search).ratio(), reverse=True)    
  print("{0} se compara con {1} el más parecido es {2}".format(search, matches, matches[0]))

En matches terminamos teniendo los elemente de la segunda lista, ordenados de mayor semejanza a menor, el primer elemento debiera ser el óptimo.

Importante: De esta forma siempre vamos a encontrar un “parecido”, como mejora adicional tal vez debas contemplar un ratio mínimo de semejanza para considerar que se ha logrado el “matching”, éste valor lo puedes definir únicamente experimentando.

Mejor aún la forma sugerida por FjSevilla por ser más compacta y por que ya incorpora la lógica para evaluar el ratio mínimo :

matches = difflib.get_close_matches(search, possibilities = lista2, n = 1, cutoff = 0.6)

Como curiosidad, faltaría indicar que difflib esta basada fuertemente en el algoritmo THE GESTALT APPROACH de 1987.

Respondido por: Anonymous

Leave a Reply

Your email address will not be published. Required fields are marked *