Мера сходства для строк в Python

Я хочу измерить сходство между двумя словами. Идея состоит в том, чтобы прочитать текст с помощью OCR и проверить результат на наличие ключевых слов. Функция, которую я ищу, должна сравнивать два слова и возвращать сходство в%. Так что сравнение слова с самим собой должно быть на 100% похожим. Я сам написал функцию и сравнил char за char и вернул количество совпадений по отношению к длине. Но проблема в том, что

wordComp('h0t',hot')
0.66
wordComp('tackoverflow','stackoverflow')
0

Но интуитивно оба примера должны иметь очень высокое сходство >90%. Добавление расстояния Левенштейна

import nltk
nltk.edit_distance('word1','word2')

в моей функции увеличится второй результат до 92%, но первый результат все еще не очень хорош.

Я уже нашел это решение для "R", и можно было бы использовать это работает с rpy2 или используйте agrepy как другой подход. Но я хочу сделать программу более и менее чувствительной, изменив эталон для принятия (принимать только совпадения со сходством> x%).

Есть ли еще одна хорошая мера, которую я мог бы использовать, или у вас есть идеи по улучшению моей функции?


person tifi90    schedule 29.11.2018    source источник


Ответы (2)


Вы можете просто использовать difflib. Эта функция, которую я получил из ответа некоторое время назад, хорошо послужила мне:

from difflib import SequenceMatcher

def similar(a, b):
    return SequenceMatcher(None, a, b).ratio()

print (similar('tackoverflow','stackoverflow'))
print (similar('h0t','hot'))

0.96
0.666666666667

Вы можете легко добавить функцию или обернуть ее в другую функцию, чтобы учесть разную степень сходства, например, передав третий аргумент:

from difflib import SequenceMatcher

def similar(a, b, c):
    sim = SequenceMatcher(None, a, b).ratio()
    if sim > c: 
        return sim

print (similar('tackoverflow','stackoverflow', 0.9))
print (similar('h0t','hot', 0.9))

0.96
None
person Martin    schedule 29.11.2018
comment
Спасибо за идею. Это помогает мне с первой проблемой, но проблема с короткими словами все еще остается без ответа. Любые другие идеи по этому поводу? - person tifi90; 29.11.2018
comment
Я не совсем уверен, почему вы хотите более высокое значение для трехбуквенного слова. Вы говорите, что интуитивно ожидали большего сходства. Строго говоря, из трех символов один различается между строками, что делает их похожими на 66%. Можете ли вы уточнить, каким должен быть ваш ожидаемый результат и почему? - person Martin; 29.11.2018
comment
Я не знаю, какой должен быть точный результат. Момент, который заставляет меня получить более высокий балл, заключается в том, что если вы сравните h0t и hxt, то интуитивно понятно, что h0t ближе к hot, чем hxt, поскольку 0 и o почти одинаковы. Только представьте, если бы это было написано от руки, вы бы не отметили h0t как неправильное, но hxt явно. - person tifi90; 29.11.2018
comment
Ну да, они эстетически похожи, я не знаю, как это проверить. Это тоже довольно субъективно, не так ли? Во всех смыслах и целях x, o и 0 одинаково не похожи друг на друга. - person Martin; 29.11.2018
comment
Я только что подумал о следующем быстром и грязном исправлении: просто сопоставьте цифры с символами с фиксированным отображением (0-> o, 5-> s, 3-> E, 9-> g,...). Поскольку я ищу настоящие слова, ноль, пять или любое другое число никогда не должно быть частью ключевого слова. - person tifi90; 29.11.2018
comment
Да, это может сработать. Просто из любопытства: вы бы скорректировали коэффициент сходства на коэффициент или просто взяли бы 5 для s, 9 для g и т. д.? - person Martin; 29.11.2018
comment
просто возьмите цифры и сопоставьте их с символами. Это работает на удивление хорошо. Я добавил еще несколько строк кода и другие правила. Например, регулировочный терм -0,1 для каждой отображаемой цифры отношения или заглавная буква i в середине слова будет отображаться на L и так далее... Я поделюсь своим результатом, когда все правила будут реализованы. - person tifi90; 29.11.2018

Я написал следующий код. попробуй. Я определил str3 для тех случаев, когда длина двух сравниваемых строк (str1 и str2) не равна. код находится в цикле while для выхода, используйте ввод k.

k=1
cnt=0
str3=''
while not k==-1:
    str1=input()
    str2=input()
    k=int(input())

    if len(str1)>len(str2):
        str3=str1[0:len(str2)]
        for j in range(0,len(str3)):
            if str3[j]==str2[j]:
                cnt+=1
        print((cnt/len(str1)*100))

    elif len(str1)<len(str2):
        str3=str2[0:len(str1)]
        for j in range(0,len(str2)):
            if str3[j]==str1[j]:
                cnt+=1
        print((cnt/len(str2)*100))

    else:
        for j in range(0,len(str2)):
            if str2[j]==str1[j]:
                cnt+=1
        print((cnt/len(str1)*100))
person Mhasa87    schedule 29.11.2018
comment
спасибо, что поделились своим кодом. Это похоже на то, что я пробовал в первую очередь. Вы получаете такие же результаты с этой функцией, как и я. Основная проблема, которую я вижу, заключается в том, что вы потеряете много информации, когда обрежете строку str3=str2[0:len(str1)]. - person tifi90; 29.11.2018