Могу ли я сделать "string содержит X" с процентной точностью в python?
Мне нужно сделать OCR на большом фрагменте текста и проверить, содержит ли он определенную строку, но из-за неточности OCR мне нужно это, чтобы проверить, содержит ли оно что-то вроде соответствия 85% для строки.
Например, я могу распознать фрагмент текста, чтобы убедиться, что он не содержит no information available
, но OCR может видеть n0 inf0rmation available
или неправильно интерпретировать количество символов.
Есть ли простой способ сделать это в Python?
Ответы
Ответ 1
Как указано gauden
, SequenceMatcher
в difflib
- это простой способ. Используя ratio()
, возвращает значение между 0
и 1
, соответствующее сходству между двумя строками, из документов:
Где T - общее количество элементов в обеих последовательностях, а M - количество совпадений, это 2.0 * M/T. Обратите внимание, что это 1.0, если последовательности идентичны и 0.0, если они не имеют ничего общего.
Пример:
>>> import difflib
>>> difflib.SequenceMatcher(None,'no information available','n0 inf0rmation available').ratio()
0.91666666666666663
Существует также get_close_matches
, который может быть вам полезен, вы можете указать ограничение расстояния, и оно вернет все соответствия на этом расстоянии от списка:
>>> 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']
Обновление: для поиска частичного соответствия подпоследовательности
Чтобы найти близкие совпадения к последовательности из трех слов, я бы разделил текст на слова, затем сгруппировал их в три последовательности слов, затем применил difflib.get_close_matches
, например:
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']
Ответ 2
Объект SequenceMatcher
в стандартном библиотечном модуле difflib
даст вам соотношение напрямую:
Ответ 3
Вы можете вычислить расстояние Levenshtein. Вот одна реализация Python: http://pypi.python.org/pypi/python-Levenshtein/
Ответ 4
Я не знаю ни одной доступной библиотеки python, которая бы делала это из коробки, но вы можете найти ее (или найти C или С++ lib и написать для нее оболочку Python).
Вы также можете попытаться свернуть свое собственное решение, основанное либо на сравнении "грубой силы" char на char, так и на правилах, определяющих "близость" между двумя заданными символами и вычисляя "точность" на основе этих правил (т.е. "o" = > "0": точность 90%, "o" = > "w": 1% точности и т.д.), или игра с более активными материалами IA (если вы не знакомы с ИА, Программирование коллективного интеллекта "может помочь вам начать работу, несмотря на несколько плохие примеры реализации).
Ответ 5
Просто для расширения на fraxel answer это позволяет найти любую произвольную длину. Извините за плохое форматирование, это сложно. Точность - это значение отсечки в 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)