Puis-je faire un "string contains X" avec un pourcentage de précision en python?
j'ai besoin de faire un peu de OCR sur un gros morceau de texte et de vérifier s'il contient une certaine chaîne mais en raison de l'inexactitude de L'OCR j'en ai besoin pour vérifier si elle contient quelque chose comme une correspondance ~85% pour la chaîne.
par exemple je peux OCR un morceau de texte pour s'assurer qu'il ne contient pas no information available
mais L'OCR pourrait voir n0 inf0rmation available
ou mal interpréter un certain nombre de caractères.
y a-t-il un moyen facile de faire cela en Python?
5 réponses
publié par gauden
,SequenceMatcher
difflib
est une voie facile à suivre. En utilisant ratio()
, renvoie une valeur entre 0
et 1
correspondant à la similitude entre les deux chaînes, de la docs:
Où T est le nombre total d'éléments dans les deux séquences, et M est le nombre de correspondances, c'est 2.0*M / T. notez que c'est 1.0 si le les séquences sont identiques, et 0,0 s'ils n'ont rien en commun.
exemple:
>>> import difflib
>>> difflib.SequenceMatcher(None,'no information available','n0 inf0rmation available').ratio()
0.91666666666666663
Il y a aussi get_close_matches
, ce qui pourrait vous être utile, vous pouvez spécifier une coupure de distance et il retournera toutes les correspondances à l'intérieur de cette distance à partir d'une liste:
>>> difflib.get_close_matches('unicorn', ['unicycle', 'uncorn', 'corny',
'house'], cutoff=0.8)
['uncorn']
>>> difflib.get_close_matches('unicorn', ['unicycle' 'uncorn', 'corny',
'house'], cutoff=0.5)
['uncorn', 'corny', 'unicycle']
mise à Jour: trouver une partielle de la sous-séquence match
pour trouver des correspondances à une séquence de trois mots, je diviserais le texte en mots, puis je les regrouperais en trois séquences de mots, puis j'appliquerais difflib.get_close_matches
, comme ceci:
import difflib
text = "Here is the text we are trying to match across to find the three word
sequence n0 inf0rmation available I wonder if we will find it?"
words = text.split()
three = [' '.join([i,j,k]) for i,j,k in zip(words, words[1:], words[2:])]
print difflib.get_close_matches('no information available', three, cutoff=0.9)
#Oyutput:
['n0 inf0rmation available']
SequenceMatcher
objet dans le difflib
le module de bibliothèque standard vous donnera directement un rapport:
vous pouvez calculer le Levenshtein. Voici une implémentation Python: http://pypi.python.org/pypi/python-Levenshtein/
Je ne connais pas de lib python disponible qui ferait cela hors de la boîte, mais vous pourriez en trouver une (ou trouver une lib C ou C++ et écrire un wrapper Python pour elle).
vous pouvez également essayer de lancer votre propre solution, basée soit sur un char "force brute" par comparaison char, avec des règles définissant la "proximité" entre deux chars donnés et calculant la "précision" basée sur ces règles (i.e. "o" = > "0": Précision de 90%, "o" = > "w": précision de 1%, etc), ou jouer avec des trucs plus impliqués IA (si vous n'êtes pas familiarisé avec L'intelligence D'affaires, le livre "Programmer L'Intelligence Collective" pourrait vous aider à démarrer, malgré les quelques exemples de mise en œuvre plutôt médiocre).
juste pour développer la réponse de fraxel, cela permet de trouver n'importe quelle chaîne de longueur arbitraire. Désolé pour le mauvais formatage, donc est difficile. La précision est la valeur de coupure dans findWords
def joinAllInTupleList(toupe):
#joinAllInTuple( [("hello", "world"),("face","book")]) = ['hello world', 'face book']
result=[]
for i in toupe:
#i is the tuple itself
carry = " "
for z in i:
#z is an element of i
carry+=" "+z
result.append(carry.strip())
return result
def findWords(text,wordSequence):
#setup
words = text.split(" ")
#get a list of subLists based on the length of wordSequence
#i.e. get all wordSequence length sub-sequences in text!
result=[]
numberOfWordsInSequence = len(wordSequence.strip().split(" "))
for i in range(numberOfWordsInSequence):
result.append(words[i:])
# print 'result',result
c=zip(*result)
# print 'c',c
#join each tuple to a string
joined = joinAllInTupleList(c)
return difflib.get_close_matches(wordSequence, joined, cutoff=0.72389)