Блог пользователя RodionGork

Автор RodionGork, 13 лет назад, По-русски

Разрабатываю библиотечку для сравнения строк с образцами. Возник вопрос который больше идеологически, нежели технический. Упрощённо говоря суть в следующем.

Задан образец некой фразы, состоящей из нескольких слов
p1 p2 ... pN
С ним сравнивается фраза, из такого же количества слов
w1 w2 ... wN
Т.е. слова разделены пробелами или ещё чем нибудь, не важно - и мы просто сравниваем каждое слово w с соответствующим по порядку образцом p. Результатом такого сравнения является, какой-то критерий e, например, количество опечаток (от 0 до length(p)) - или в принципе какая-то "похожесть" в промежутке [0, 1]... или ошибочность (в том же промежутке... или от 1 до +inf... Критериев можно много придумать и их несложно друг из друга получить... В общем, будет у нас N оценок:
e1, e2, ... eN.

Так вот. Вопрос в том - как оценить "похожесть" (или "релевантность") полного образца (из N элементов) и целой фразы (из N элементов).

Например, сначала я использовал для соответсвия слова элементу образца критерий "ошибочность" (от 0.0 до 1.0) и для фразы в целом брал "ошибочность" как max{e}.

Однако, получалось что если скажем у меня четыре слова, и три из них без ошибок, а в одном ошибочность равна 0.5, то фраза целиком не проходила, если порог установлен например 0.3.

Тогда я стал считать их среднее геометрическое. Точнее среднее геометрическое величин, дополняющих "ошибочность" до 1 (назовём это "похожестями"):
etotal = 1 - (П(1-ei))1/N

С этой оценкой хорошо то, что если одна из "ошибочностей" равна 1.0, то и общая ошибочность тоже будет 1.0, а если все "ошибочности" равны, то общая "ошибочность" равна ошибочности каждого из элементов.

Теперь однако выходит что если, например, сравнивается фраза из 3 слов и из них два безошибочны, то третье может иметь ошибочность около 0.65... Т.е. в общем оно может оказаться почти непохожим на элемент образца.

Ну и хуже всего что мне не хватает знаний чтобы решить, разумен ли в общем случае какой-то из этих способов - или может лучше использовать какой-то другой, а также чтобы обдумать возможные сложности которых я пока не нашёл. Проблема в том что я потихоньку внедряю этот функционал в проект и полезно заранее продумать возможные косяки, т.к. когда он уже хорошо внедрится, переделывать будет гораздо сложнее.

Так что буду рад и благодарен любым подсказкам, советам, идеям и возражениям.

  • Проголосовать: нравится
  • +3
  • Проголосовать: не нравится

13 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
Мне кажется, что вне контекста трудно о чем-либо говорить; не очень понятно, какая именно у Вас ситуация. Скажем, если речь идет о случайных наборах букв, так это одна ситуация - но здесь, насколько я понимаю, другой случай. А если берутся предложения из реальной жизни, но, возможно, с опечатками , и надо узнать, может ли набранный текст быть одним из фиксированных типичных предложений  - это другая ситуация. В зависимости от целей, очевидно, и формулы будут разные.
  • 13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    Это верно, но к сожалению я не могу подметить каких-то "выразительных особенностей" обрабатываемого текста и поэтому решил на них не затачиваться. Фразы часто состоят из имён собственных, аббревиатур... Но могут содержать и более произвольные слова. Могут содержать "слова" являющиеся записью чисел (для таких случаев используется специальный элемент образца, результатом сравнения с которым является либо строго 0, если слово является числом и в нужный диапазон входит, либо 1 в противном случае).

    Скажем "Барак Х Обама 2" - здесь два имени собственных, аббревиатура и числовое значение.

    Т.е. я исхожу из пожелания, что механизм должен быть робастным - т.е. чтобы он был адекватен для возможно большего количества случаев, хотя может механизмы заточенные под специальные случаи вели бы себя лучше для этих специальных случаев и хуже для остальных.
13 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
Нужно сначала узнать, какую задачу в проекте вы пытаетесь решить с помощью вычисления «похожести». Без этого вообще бессмысленно обсуждать адекватность методов. Я правильно понимаю, что нужно искать точные фразы, но при этом нет уверенности, что они записаны без ошибок, связанных с клавиатурным набором?
  • 13 лет назад, # ^ |
    Rev. 3   Проголосовать: нравится +1 Проголосовать: не нравится

    Изначально я делал этот механизм чтобы определить, например, название какой из 60+ станций метро имел в виду пользователь.

    Т.е. станции могут быть записаны сокращённо, с ошибками или вообще нестандартно. Кроме того есть станции с похожими названиями:
    Московская - Маяковская
    Московская - Московские ворота
    Ленинский проспект - площадь Ленина (проспект и площадь могут сокращаться до пр. и пл. например, ну и "ленинский" может быть написан не полностью)
    Невский проспект, он же Канал Грибоедова, он же Гостиный двор. К "каналу" может быть присобачена "наб."...
    Площадь Александра Невского - может иметь довольно много вариантов сокращений

    В общем получается есть одна строчка и полсотни образцов. Мне хотелось создать механизм который бы позволял удобно перечислить эти образцы, скажем, в массиве - а потом вызывать для каждой проверяемой строки единственную функцию для выбора лучшего совпадения... Я об этом в прошлом посте жаловался...

    В общем, механизм-то я создал, но тут заметил что благодаря подстановкам, кроме метро им ещё много вещей можно обрабатывать в моём проекте, например запись размера может быть:
    * просто числом "50"
    * диапазоном "30-40"
    * с присловьем "от 30", "меньше 40" или "от 30 до 40"
    Или название предмета:
    * стиральная машина (стир.маш. и т.п.);
    * автомобиль (машина и т.п.)
    * холодильник (2-дв х-к и т.п.)

    Так что задачи стали довольно общими...

    Конечно при задании мне приходится учитывать различные возможные варианты (этого за меня комп не осилит), но по крайней мере они сводятся в одну строку, например вышеупомянутый размер записывается через "ИЛИ" из следующих альтернатив:
    * ЧИСЛО заменяется на "ЧИСЛО ЧИСЛО"
    * ("до" или "меньше") ЧИСЛО заменяется на "0 ЧИСЛО"
    * ("от" или "больше") ЧИСЛО заменяется на "ЧИСЛО INF"
    * ЧИСЛО1 ("-" ИЛИ ":" ИЛИ "/") ЧИСЛО2 заменяется на "ЧИСЛО1 ЧИСЛО2"
    * "от" ЧИСЛО1 "до" ЧИСЛО2 заменяется на "ЧИСЛО1 ЧИСЛО2"
    Получается что-то вроде... Хм... В общем я не нашёл как тут тег "pre" сделать, сорри... %)
13 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
Тема исправления опечаток мне во многом близка, поэтому напишу всё что я об этом думаю.

Исправление опечаток обычно эквивалентно максимизации некоторой величины, и очень важно понимать её физический смысл. В Вашем случае это, скорее всего, условная вероятность того, что пользователь имел ввиду pi при условии, что он писал wi. Стоит заметить, в самой распространённой существующей модели ошибок (noisy channel) эта условная вероятность равна P(p)/P(w)*П(1-ei). (здесь P - частота конкретной фразы среди всех запросов). Чтобы сэкономить Вам время скажу по поводу модели "noisy channel", что если 1-ei = exp(-dist(pi, wi)), где dist - почти симметричная относительно свапа p и w функция, то Вы скорее всего довольно близки к этой модели. Если считать P(w) фиксированным, то задача состоит в максимизации произведения P(p)*П(1-ei). Обычно имеет смысл делать замену если P(p)/P(w)*П(1-ei) - величина порядка единицы. При этом для вычисления P разумно пользоваться чем-нибудь типа статистического словаря и считать все слова независимыми. Тогда общая формула превратится в П(P(pi)/P(wi)*(1-ei)). И именно эту величину разумно сравнивать с каким-нибудь 0.7.