Comments 43
В поисковых системах какой алгоритм применяется в поисковой строке?
Вам нужен стемминг. Можете попробовать стеммер Портера.
Простой коэффициент Жаккара не подойдёт?
Cosine similarity ещё, https://en.wikipedia.org/wiki/Cosine_similarity, но оно в общем случае считает все перестановки одинаковыми (похожесть кот
на ток
равна 1). Иногда это очень нужная фича.
Я что-то похожее писал на коленке лет 28 назад, для быстрого поиска имён в адресной книге (поиск по мере набора имени). Там я добавил идею о близком равенстве отдельных множеств букв. Например, буквы е и ё можно считать равными, а буквы с и з, и и е, д и т - близкими. Ну и так далее. Также, учитивались возможные удвоения. Хоть алгоритм был придуман и написан на коленке, но для имён/фамилий он работал очень неплохо.
Держите лучше расстояние Карловского:
function karlovskiy_distance( left: string, right: string ) {
left = '\b\b' + left + '\f\f'
right = '\b\b' + right + '\f\f'
let dist = -4
for( let i = 0; i < left.length - 2; ++ i ) {
if( !right.includes( left.slice( i, i+3 ) ) ) ++ dist
}
for( let i = 0; i < right.length - 2; ++ i ) {
if( !left.includes( right.slice( i, i+3 ) ) ) ++ dist
}
return Math.max( 0, dist ) / ( left.length + right.length - 8 )
}
я пришёл к себе домой | я пришел домой к себе = 0.29
июнь | июль = 0.25
кот | для = 1
кот | кот = 0
Чем лучше? А чем хуже?
Простой и быстрый алгоритм.
Нормированный от 0 до 1 результат.
Перестановка слов не даёт большой дистанции.
Маленькие разные слова не дают маленькой дистанции.
Не даёт преимущества началу и концу.
Различает начало и конец.
Работает и со строками разной длины.
Годится только для коротких строк.
Сложность o(n) .. O(n^2)
Не сложно потратить O(log n) памяти и сделать O(n) поддержав заодно и длинные тексты.
А, хотя, запилил библиотечку $mol_text_distance для любых текстов с O(n).
Ответ всегда должен получаться от 0 до 1, где 0 - точное совпадение слов, 1 - полное не совпадение слов.
Что-то не сходится. 0 может быть только если не совпала ни одна буква.
То есть для примера сравним варан и комод.
Расстояние по вашей формуле равно нулю, но слова совсем не похожи.
Верно подметили.
На самом деле ровно наоборот: 1 - точное совпадение, 0 - полное не совпадение.
Это написано тут, например. Или даже банально на англ вики
Я подозреваю путаница возникла так как автор поста подсмотрел на рус вики, где сейчас стоит как раз непровереная версия статьи с неверная информация по поводу ответов.
Нечёткое сравнение строк https://habr.com/ru/post/341148/
Какая здесь теплая лаповая атмосфера! Друзья, а может быть у кого-нибудь появится хорошая идея или он что-то видел похожее насчет задачи, которую лично мне было бы интересно решить. Задача в следующем.
У вас есть достаточно длинный текст на естественном языке, похожем на английский или русский, однако в нем удалены все пробелы между словами, все знаки препинания и все большие буквы заменены маленькими. Можно ли не пользуясь словарями и любыми другими источниками данных придумать алгоритм, который достаточно точно поделит этот текст на слова?
Разве что нарезать по словарю невозможных биграм. А кто и зачем эти пробелы вырезал?
Так, словаря по условию нет, грамматика не известна, тренировка на сторонних данных запрещена.
Задача - праздный вопрос. В устной речи нет пробелов и заглавных букв. Также мне известны искусственные языки, смысл предложений в которых задается их грамматикой. Не точно, конечно, но с точностью до изоморфизма. Сообщения на таких языках вы сможете послать любой разумной расе во вселенной безо всякого переводчика или предположений о подобии их культуры нашей и они вас поймут.
В связи с этим появился праздный вопрос, на сколько грамматическая и смысловая структура естественных языков может быть выявлена из статистических закономерностей речи.
Сообщения на таких языках вы сможете послать любой разумной расе во вселенной безо всякого переводчика или предположений о подобии их культуры нашей и они вас поймут.
Это не реально, чтобы сообщение мало-мальски было понятно нужно посылать видео файлы или наборы фотографий. Любой текст и любая грамматика требует общей культуры и логики, либо долгого обучения.
Я тоже думал, что невозможно. Так много, где утверждается - но все эти утверждения ошибочны.
Хорошо исписанная тетрадь по арифметике 3-го класса не самым неряшливым и отсталым учеником содержит достаточно закономерностей, чтобы быть понятной любой достаточно развитой цивилизации, даже если та никак не знакома с культурой Земли.
Банально, у них давно все на биологических компьютерах с системой счисления по основанию пи без целых и отрицальных чисел в принципе, а тетрадка с закорючками вообще не воспринимается как носитель информации.
достаточно развитая - значит способная воспринимать закономерности окружающего мира и формировать новые понятия. Символьные последовательности в тетрадке по арифметике проявляют закономерности. Основываясь на них, разумная цивилизация сможет сформировать новое понятие десятичной арифметики и натурального числа, даже если до этого они ей не были известны. Чем они думают и какая у них математика - не важно.
Символьные последовательности в тетрадке по арифметике проявляют закономерности. Основываясь на них, разумная цивилизация сможет сформировать новое понятие десятичной арифметики и натурального числа, даже если до этого они ей не были известны
Ну вы считаете себе представителем разумной цивилизации? Ну вот вам математическая запись
Сможете рассказать, какие математические формулы там записаны не используя гугл или хотя бы как вы сможете понять закономерности? Учитывайте, что это все-таки Земная цивилизация наш предок, от которой мы унаследовали многие принципы современной цивилизации. Сложность расшифровки записей инопланетной цивилизации может быть на пару порядков выше.
Обратите внимание, вы не знаете тут ни систему счисления, ни в какую сторону записываются формулы, ни какие символы будут символами операций, ни как записывается числа (десятичная позиционная система далеко не единственная возможная), более того у вас совершенно нет понятия, какие математические действия тут вообще записаны, может 2+2, а может двойные интегралы, с производными, синусами и косинусами.
Даже если у вас совпадает математическая логика, ни зная ничего о записавшей цивилизации, расшифровка тут очень нетривиальна. Если же понятия совсем разные — практически невозможна.
Ваша земная тетрадка по математики для инопланетян, которые вообще ничего про Землю не знают, тоже скорее всего будет просто набором символов. По-крайне мере утверждать, что Любая цивилизация легко ее расшифрует очень уж антропоцентричное утверждение (предположение, что инопланетная цивилизация условных плазменных сгустков имеет схожую логику, принципы математики, системы записи формул и т.п.)
Я даже больше скажу, даже современные математики всё никак не придут к консенсусу которая из уже существующих математических логик более корректна.
Простите, что разрушил ваши представления о мире, я сам был обескуражен, когда впервые осознал эти идеи.
Теперь, что касается вашего манускрипта. Если там действительно проявляются закономерности, то можно попытаться их найти. Текста мало, откровенно мало, на исписанную тетрадь не тянет, хотя отдельные "буквы" в общем-то просматриваются. Сам я конечно же не стану тратить вечер или неделю, чтобы решить этот ребус, когда он уже кем-то решен. Но, если бы он не был решен, или тем более был посланием из космоса, то пара сотен умнейших людей лбы над ним бы поморщило.
Минимизируешь энтропию текста деленного на слова + энтропию словаря, по всем разбиениям. Если делить посимвольно (все слова из одной буквы), словарь получаеться маленький, а текст большой. С другой стороны если взять весь текст как одно слово - тогда на сам текст будет приходиться 0 энтропии, а словарь будет стоить как весь текст без сжатия (с перплексией алфавит на символ). При этом частые сочетания (фразеологизмы) и популярные предлоги скорее всего слипнуться в одно слово. Еще можно добавить штраф за длину слов / KLD между словарем и ципфром.
Как считать энтропию словаря? Энтропия одноэлементного множества не равна нулю?
log(alphabet) * сумму длин всех слов.
Я попробовал что получается на тексте полученном из статьи, написал жадный алгоритм, сейчас посмотрим что выйдет.
Начинаю с односимвольных слов, сливаю соседние жадно.
Вот концовка
Видно что жадность плохо работает, нужно еще и пересобирать слова.
Пример: "есл им ы" встречается 4 раза, и хотя мы добавили в словарь пару (есл, и), мы не можем ничего сделать с уже построенным "им".
Красиво. Даже на маленькой статье вырисовываются знакомые очертания некоторых слов. А томик войны и мира ваша программа переварить сможет?
Асимптотика не та, но я попробовал.
315058.332 204.849 гово ри 49 41162 394
314857.649 200.682 ихай лов 28 41134 394
314657.976 199.673 нул ся 30 41104 395
314547.888 110.087 лов на 73 41053 396
314315.691 232.197 че лов 49 41004 397
314123.157 192.534 напа в 51 40953 398
313921.508 201.648 пер е 71 40882 399
313741.424 180.084 ма лень 27 40855 400
313551.339 190.086 гово рила 29 40826 401
313376.408 174.931 кото рый 26 40800 402
298986.794 256.386 сказа л 78 36302 622
298732.565 254.230 челов е 49 36253 622
298492.642 239.922 княги ня 42 36211 623
298281.436 211.206 те перь 30 36181 623
298093.330 188.106 петер бур 17 36164 623
297918.569 174.761 васи лий 23 36141 624
297746.231 172.338 про дол 29 36112 625
297587.984 158.247 прос и 42 36070 626
297442.206 145.777 какбуд то 29 36041 627
297289.781 152.426 графи ня 27 36014 628
297156.175 133.605 приба ви 19 35995 628
297040.460 115.715 все гда 17 35978 628
296925.564 114.897 улыба ясь 19 35959 629
296811.075 114.488 стве нно 22 35937 630
296681.633 129.442 сказа лаона 28 35909 631
296573.243 108.390 с мотре 24 35885 631
296472.848 100.395 м ихайлов 26 35859 632
Что-то получилось https://pastebin.com/6xk0ZipK
Ну, зато идея простая и интересная. На асимптотику вы кстати еще не вышли. Я подозреваю, если ваш алгоритм масштабировать на ленинскую библиотеку, то размер словаря перестанет быть сильным ограничением и в него начнут попадать частые словосочетания или даже целые крылатые фразы. Но мне все равно понравилась ваша мысль насчет энтропии. Быть может через годик другой она дозреет до результата достойного научной статьи.
Я имел в виду time complexity, у меня что-то между O(n^2) и O(n^3).
Вот тут код, я наигрался с ним, как минимум убедился что моя идея рабочая https://pastebin.com/uWnsdikr
Да, я как-то не заметил: вы "энтропию" текста делите на количество "слов" в нем. Для больших текстов разве не будет наблюдаться тенденции к измельчению "слов", чтобы увеличить делитель большого слагаемого?
Я нигде ничего не делю, энтропия считается для всего текста. Если его сжать арифметическим кодеком приложив частотный словарь слов, то ровно столько бит потребуется для сохранения. Вот со словарем я немного упростил функцию. Как раз наоборот, чем меньше слов, тем меньше энтропия текста (но больше словарь).
Можно даже упростить задачу. Взять текст на русском, английском или (не дай бог) немецком языке и удалить все точки. Даже в такой постановке словаря будет недостаточно для восстановления точек.
Можете проверить на таком примере:
"Вы встретили Машу в Москве Маша жила на шоссе Энтузиастов в большом доме"
Почему вы думаете, что разбить на предложения проще, чем на слова?
Как минимум потому, что мы имеем очевидные подсказки для возможных расположений точек: конец строки или большая буква в следующем слове.
Для разделения потока символов на слова у нас даже этого нет.
При перестановкЕ! Не И, пожалуйста поправьте.
Н-граммы разной длины во всех своих проявлениях и хаки с сортировкой слов по буквам (вот оригинальный блог пост).
В сочетании с существующими библиотеками по оптимизированному расчету расстояний Левенштейна или KNN (k-nearest neighbour search) можно сделать поиск и индекс любой сложности и нужности.
Мне кажется у Джаро есть недостаток. Этот алгоритм не отражает то, что человек "подразумевает" под похожестью.
В статье сравниваются слова:
создание
обедать
И итоговое расстояние получается:
d = (1 / 3) * ( 3 / 8 + 3 / 7 + (3 - 0.5) / 3 ) ≈ 0.33 * ( 0.36 + 0.43 + 0.83 ) ≈ 0.53
Предположим мы уберем лишнюю, не совпадающую букву "с".
оздание
обедать
Тогда слова должны стать "более похожими", но изменится выравнивание букв "да". И это значительно изменит результат алгоритма.d = (1 / 3) * ( 3 / 7 + 3 / 7 + (3 - 1) / 3 ) ≈ 0.33 * ( 0.42 + 0.42 + 0.33 ) ≈ 0.39
Получается, убрав лишнюю букву, которая мешала совпадению, мы только уменьшили "похожесть". А вот расстояние Левенштейна тут покажет правильную тенденцию.
Как работает неточное сравнение строк