Який алгоритм ви б найкраще використали для подібності рядків?


23

Я розробляю плагін для унікального визначення вмісту на різних веб-сторінках на основі адрес.

Тож у мене може бути одна адреса, яка виглядає так:

1 someawesome street, anytown, F100 211

пізніше я можу знайти цю адресу в дещо іншому форматі.

1 someawesome street, F100 211,

або, можливо, так само невиразно

someawesome street F100

Це технічно однакова адреса, але з рівнем схожості. Я хотів би: а) створити унікальний ідентифікатор для кожної адреси, щоб здійснити пошук, і б) з'ясувати, коли з’явиться дуже схожа адреса.

Які алгоритми / методи / Строкові показники мені слід дивитись? Відстань Левенштейна здається очевидним вибором, але цікавим, якщо є якісь інші підходи, які б тут піддалися.


"Левенштейнська відстань" - це не алгоритм.
gnasher729

Якщо ви не введете якийсь основний синтаксичний аналіз, сира відстань Левенштейна не буде такою приємною. Вам слід спробувати визначити хоча б слова, які можуть бути назвами вулиць, міст та ін., А також ті, які можуть бути номерами вулиць або поштовими індексами. Тоді, можливо, застосуйте Левенштайн до них за допомогою якогось нечіткого статистичного відповідника, що живиться реальними місцями / назвами вулиць.

7
@gnasher: Але функція, яка обчислює відстань Левенштейна, є алгоритмом. Без такої функції відстань Левенштейна - це лише інтелектуальна цікавість.
Роберт Харві

Я знайшов дуже практичне пояснення з прикладами тут: порівняння алгоритмів . На закінчення вони рекомендують використовувати подібність Яро-Вінклера, оскільки алгоритм Левенштайна залежить від довжини рядка, тому порівняти їх не корисно.
Сандра Менезес

Відповіді:


14

Алгоритм Левенштайна заснований на кількості вставок, видалень та підстановок у рядках.

На жаль, він не враховує поширену помилку, яка полягає у перенесенні двох знаків (наприклад, деякий у порівнянні з деяким). Тому я вважаю за краще більш надійний алгоритм Дамерау-Левенштейна .

Я не думаю, що застосовувати відстань на цілі рядки не дуже добре, оскільки час різко збільшується в порівнянні з довжиною рядків. Але ще гірше, коли компоненти адреси, як-от ZIP, видаляються, зовсім інші адреси можуть відповідати кращому (вимірюється за допомогою онлайн-калькулятора Левенштайна ):

1 someawesome street, anytown, F100 211       (reference) 
1 someawesome st.,anytown                     (difference of 15, same address)     
1 otherplaces street,anytown,F100211          (difference of 13, different ddress) 
1 sameawesome street, othertown, CA98200      (difference of 13, different ddress)
anytown, 1 someawesome street                 (28 different same address)
anytown, F100 211, 1 someawesome street       (37 different same address)

Ці ефекти, як правило, погіршуються для коротшої назви вулиці.

Тож вам краще використовувати розумніші алгоритми. Наприклад, Артур Ратц опублікував на CodeProject алгоритм для розумного порівняння тексту. Алгоритм не роздруковує відстань (він, безумовно, може бути відповідним чином збагачений), але він визначає деякі складні речі, такі як переміщення текстових блоків (наприклад, заміна між містом та вулицею між моїм першим прикладом та моїм останнім прикладом).

Якщо такий алгоритм занадто загальний для вашого випадку, вам слід реально працювати за компонентами та порівнювати лише порівнянні компоненти. Це непроста річ, якщо ви хочете проаналізувати будь-який формат адреси у світі. Але якщо ціль більш конкретна, скажімо, США, це, безумовно, можливо. Наприклад, "вулиця", "вул.", "Місце", "плацза" та їхні звичайні написання можуть вказувати вуличну частину адреси, провідною частиною якої в принципі буде номер. Поштовий індекс допоможе знайти місто, або, мабуть, це останній елемент адреси, або якщо вам не подобається здогадування, ви можете шукати список назв міст (наприклад, завантажити безкоштовну базу поштових індексів). Потім ви можете застосувати Дамерау-Левенштайн лише для відповідних компонентів.


Що щодо сортування обох рядків порівняння перед порівнянням? Я виявив, що це може допомогти при переміщенні.
openwonk

2

Відстань Левенштейна краще для слів

Якщо слова (в основному) написані правильно, то подивіться на мішок слів . Мені може здатися, що над убиванням, але TF-IDF та косинусна схожість .

Або ви можете скористатися безкоштовним люценом. Я думаю, що вони роблять косинусну схожість.


1

По-перше, вам доведеться розбирати веб-сторінку за адресами, RegEx - це написано, але це може бути дуже складно для розбору адрес за допомогою RegEx. Вам, швидше за все, доведеться переглядати список потенційних форматів адресації та великий один чи більше виразів, які відповідають їм. Я не надто знайомий з розбором адрес, але рекомендую поглянути на це запитання, яке відповідає аналогічній лінії думки: Загальний аналізатор адреси для тексту Freeform.

Відстань Левенштейна корисна, але лише після того, як ви розділили адресу в її частині. Розглянемо наступні адреси. 123 someawesome st.і 124 someawesome st.ці адреси є абсолютно різними місцями, але відстань Левенштейна становить лише 1. Це також можна застосувати до чогось подібного 8th st.і 9th st.подібні назви вулиць зазвичай не відображаються на одній веб-сторінці, але це не є нечуваним. На веб-сторінці школи може бути, наприклад, адреса бібліотеки, або церква в декількох кварталах. Це означає, що єдиними даними, за якими відстань Левенштейна легко використовувати, є відстань між двома точками даних, наприклад, відстань між вулицею та містом.

Що стосується з'ясування того, як розділити різні поля, то досить просто, коли ми отримаємо самі адреси. На щастя, більшість адрес надходять у дуже специфічних форматах, за допомогою трохи майстра RegEx повинно бути можливим розділити їх на різні поля даних. Навіть якщо адреса не буде добре відформатована, все ще є надія. Адреси завжди (майже) відповідають порядку величини. Ваша адреса повинна лежати десь на такій лінійній сітці, як ця, залежно від того, яка кількість інформації надається та що це:

StreetNumber < Street < City < State < Country

Це трапляється рідко, якщо взагалі адреса пропускає з одного поля в не сусіднє. Ви не збираєтеся дуже часто бачити вулицю, а потім країну або StreetNumber, а потім місто.


2
За винятком того, що адреси вулиць не є регулярними і їх неможливо надійно розібрати за допомогою регулярних виразів. Вони, звичайно, не можуть бути точно визначені, якщо вони просто вбудовані у вільний текст. Звичайно, ви можете написати кілька різних регулярних виразів, щоб відповідати різним загальним форматам, якщо ви вже знаєте, де шукаєте.
Марно

@Useless Це правда. Теоретично це можливо, але я недооцінив обсяг роботи, необхідний для його внесення. Особливо, коли є потенційно кращі варіанти. Я змінив свою відповідь, щоб відобразити це.
Уценна

1

Ви запитуєте про алгоритми подібності рядків, але ваші рядки - це адреси. Я б надіслав адреси в API місцеположення, наприклад, в Google Search Place Place і використав би їх formatted_addressяк точку порівняння. Це здається найбільш точним підходом.

Для адресних рядків, які не можуть бути розташовані через API, ви можете повернутися до алгоритмів подібності.


1
+1 Аутсорсируйте це, щоб ви отримали владу експертів виконати роботу за вас. Не обов'язково бути Google, оскільки там є кілька постачальників послуг. Не витрачайте час на це, якщо відповідність адреси не є вашим основним бізнесом.
LoztInSpace

0

Один класний алгоритм, який корисний, але вимагає встановленої бази даних попередніх відповідей, називається: Рядок редагування рядків.

Відстань редагування рядків, як функція, може повернути назад "наскільки різні ці два слова".

Такі слова, як "догма" та "собака", ви отримаєте значення 3 (для 3 зайвих символів).

Або "кішка" і "капелюх", отримайте назад значення 1 (для одного іншого символу).

(Джерело: https://en.wikipedia.org/wiki/Edit_distance )


2
Яка перевага перед згадуваним ОП «Левенштейн»?
Крістоф

-1

Дійсно, використання деякої функції дистанції здається хорошим підходом. Але проблема полягає в тому, щоб знайти найближчий рядок із заданої адреси, що далеко не банально.

Ви описуєте тут широку категорію алгоритмів. Перевірити Найближчий сусід

Як зазначалося в коментарі, якщо ви знайдете спосіб розділити компоненти адреси (назва вулиці, номер тощо), це полегшить завдання.


-1

LongestCommonSubsequence (від тексту Apache commons-text) може бути іншим підходом до спроб з адресами. Якщо ви визначаєте подібність двох як відношення " загальної довжини підрядності / макс (довжини адреси) ", то ви можете застосувати поріг допуску - наприклад, 0,8, який визначатиме відповідність / не відповідає. Таким чином, ви зможете збігати адреси на зразок " 1 якась чудова вулиця, будь-який місто " та " 1 якась чудова вулиця. Будь-яка місто ".

Це не надто швидкий алгоритм, тому ви можете застосувати швидкі відмови, щоб мінімізувати порівняння. Прикладом може бути - уникайте порівняння, якщо поштові індекси не збігаються або інша послідовність вилученої цифри відрізняється.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.