Comments 31
На сколько я понимаю, ваш набор правил специфичен для какого-то одного региона.
Дело в том, что если посмотреть в данные "ФИАС", то видно, что типов объектов, которые вы перечислили в списке замен, больше.
По моему опыту, проблемы возникают в случаях, когда краткий или полный тип объекта может быть неотъемлимой частью имени объекта. Для примера возмем что-то "Максима Горького".
Возможны разные варианты записи: "АК 24 Горького", "Волгоградская (М.Горького)", "Володарского/Максима Горького", "гк Протон (ул Горького)", "ГМ ул 2-я М.Горького", "им Горького", "им. Горького","им.Горького","им Горького","им Горького А.М.","им Горького А.М.угол ул. Челюскинцев","им. М. Горького","им. М.Горького","им.М.Горького", и т.п. более сотни вариаци. В данном случае, "м" и "м." - так же является сокращением от "местечко", "ул" - сокращение от "улица". Запятые, точки, тире, скобки, тоже могут быть существенной частью имени объекта.
На каких выборках вы проверяли свой вариант сопоставления адреса? Вы проводили анализ, сколько адресов у вас выпадало в "отсев" (отмечены флажком is_approved=false) и какие из них в действительности были записаны корректно? Что вы предполагаете делать с адресами попавшими в "отсев"?
Я сам занимался адресным реестром в течении некоторого количества времени но так и не нашёл самого оптимального и точного способа проверки адресов. Все попытки разбиваются об факт того, что адрес изначально в ФИАС может быть уникальным или быть внесен оператором неверно.
А какие объемы выборки у вас? И сколько это занимает по времени примерно?
Решал подобную задачу Правда, у нас сравнение двух наборов адресов - А (порядка 96 000 000 адресов) и Б (порядка 8 000 адресов) с условием что "все элементы адреса из набора Б должны входить в адрес из набора А". При этом допускаются ложноположительные результаты (они уходят на ручной разбор), но не допускаются результаты ложноотрицательные.
Позже в этот алгоритм, для сокращения количество ложноположительных результатов, был добавлен фильтр по числовым элементам адреса - чтобы адрес типа "ЛЕНИНА 2 5" не давал совпадений с адресом "ЛЕНИНА 5 2".
В конечном итоге удалось получить время работы порядка 15-20 минут на промсреде.
Кажется, что в наше время такого рода задачки уже можно решать гораздо менее скромными усилиями, с лУчшим результатом и за гораздо мЕньшее время. Посудите сами. Любопытства ради, не заморачиваясь сколь-нибудь всерьез, я взял ваш пример из начала статьи, на быструю руку накидал промпт, и попросил LLM решить вашу задачку. Промпт выглядит так: "Я дам тебе список адресов, среди которых встречаются одинаковые, на записанные по-разному. Найди адреса, которые являются одними и теми же, пусть и записанными по-разному, и составь из них новый список, в котором будут присутствовать только уникальные адреса. Запиши адреса в этот список единообразно по следующему шаблону: {Населенный пункт}, {Улица}, {Дом/квартира и т.п.} <адреса>"д. Малое Шилово, ул. Березовая, д. 7"; "п. Ласьва, ул. Весенняя, д. 5"; "Луговой пер 5, Краснокамск г"; "д. Новая Ивановка, ул. Солнечная, 18"; "Весенняя 5Ласьва"; "д.Новая Ивановка, ул.Солнечная, 18"; "Березовая 7М Шилово"; "г. Краснокамск, пер. Луговой, 5"</адреса> Мой список адресов слегка отличается от вашего, я решил, что не стоит облегчать задачу ИИ, и разбил пары похожих адресов. Ответ ChatGPT-4: "
Для составления списка уникальных адресов необходимо:
Привести все адреса к единому шаблону.
Удалить дубликаты, учитывая их разные написания.
Общий шаблон: {Населенный пункт}, {Улица}, {Дом/квартира}
.
Результат обработки:
д. Малое Шилово, ул. Березовая, д. 7
п. Ласьва, ул. Весенняя, д. 5
г. Краснокамск, пер. Луговой, д. 5
д. Новая Ивановка, ул. Солнечная, д. 18
Если требуется пояснение, как именно это было сделано, дайте знать!"
Этот же промпт я отправил в Claude Sonnet 3.5 и получил такой ответ: "
д. Малое Шилово, ул. Березовая, д. 7
Исходные варианты:
"д. Малое Шилово, ул. Березовая, д. 7"
"Березовая 7_М Шилово"
п. Ласьва, ул. Весенняя, д. 5
Исходные варианты:
"п. Ласьва, ул. Весенняя, д. 5"
"Весенняя 5_Ласьва"
г. Краснокамск, пер. Луговой, д. 5
Исходные варианты:
"Луговой пер 5, Краснокамск г"
"г. Краснокамск, пер. Луговой, 5"
д. Новая Ивановка, ул. Солнечная, д. 18
Исходные варианты:
"д. Новая Ивановка, ул. Солнечная, 18"
"д.Новая Ивановка, ул.Солнечная, 18"
"
Получив такой ответ, я попросил Sonnet очистить вывод: "Ок, верни только список, без исходных вариантов и твоих комментариев." Ответ: "
д. Малое Шилово, ул. Березовая, д. 7
п. Ласьва, ул. Весенняя, д. 5
г. Краснокамск, пер. Луговой, д. 5
д. Новая Ивановка, ул. Солнечная, д. 18
"
На самом деле, если потратить чуть больше времени, то можно добиться от LLM ответов в любом желаемом формате. А если еще навостриться использовать API, то можно решать и не такие задачки.
Так только кажется. Попробуй нагрузить эту штуку реальной работой и получишь много глупостей и большой счет в подарок.
Гружу. Получаю результат - аж дух захватывает. Но я не настаиваю, пусть каждый пользуется теми инструментами, которые ему нравятся, и с которыми у него получается лучше.
Как круто сливать корпоративные данные куда-то на аутсорс и еще платить за это! Ведь написать регулярку для решения простой задачи это так сложно, а вот подключаться к какой-то левой апишке, писать промпты и настраивать пайплайн для закидывания денег на счет, обработки данных и т.д. -- это просто!
Сразу видно человека, который код не пишет, а занимается профанацией.
Сильное утверждение, но настоящим провидцам можно и не такое. Однако в данном случае ваши телепатические возможности вас несколько подвели. Я бы сказал, что подвели буквально по всем пунктам.
Не очень понятно откуда вы взяли про слив данных. Какую-то свою параллель с упоминанием LLM провели?
Что мешает решать это своими мощностями?
Решаю постоянно такие мелкие задачи, как причесать списки, отсортировать, сопоставить и прочее локально на ноутбуке. Можно конечно постоянно кодить, но зачем? Спортивный интерес? Если что-то решает рутину в пару кликов - почему бы и нет.
Для использования LLM вовсе необязательно "подключаться к левым апишкам". Существует огромное количество LLM, которые можно поднять локально на своём железе, да ещё и дообучать на нужных данных.
Я активно использую chatgpt, gemini, gigachat.
Большие объемы они обрабатывают крайне неохотно и ленятся - сделают первые 10 или 50 строк и "дальше продолжайте по выбранному шаблону" :) Или пропускают строки - говорю начни с 275 строки. А он такой - начинаем с 245 :)
Для десятка строк - хорошее решение, для сотен - нужен скрипт.
А если давать не большие объемы, а адекватные?.. Помня о крайне ограниченном размере возможного ответа, какой смысл давать большие объемы для этой задачи?.. Если отправлять небольшими порциями, используя API, да еще и организовав проверку ответов с коррекцией в случае необходимости?.. А скрипт для решения вашей задачи нужен, а иначе как вы будете использовать API? Но этот скрипт будет несравенно проще, нежели те, что вы используете для решения этой задачи. Ну и уточню, что ответы ChatGPT и Sonnet 3.5 я привел в качестве демонстрации возможности LLM решить эту задачу. Для большого объема входных данных надо будет использовать API, я подумал, что это достаточно очевидно, но, судя по комментариям, я ошибался в этом.
Лично я сложности не вижу :)
На вкус и цвет все инструменты разные - кому-то одни нравятся, кому-то другие. Это ведь не значит что одни чем-то хуже или лучше
На вход к 4o-mini можно подать ~128000x4 символов и получить ответ размером ~16000x4 символов. Если задача - простой перевод текста то более менее справляется с большими объемами. Если цифры и таблицы то это вообще забей, даже простую сортировку испортит.
Мало привести адрес к формальному виду, еще неплохо бы проверить его на реальность. :)
Когда на предыдущем месте работы возникла задача по рассылке ~10000 бумажных писем в месяц (работа с клиентами банков, у которых была отозвана лицензия) - оказалось, что адреса в базах записаны как попало, и многие - с ошибками. Поэтому сначала руководство попыталось организовать проверку вручную (на сайте Почты России, они сейчас тоже сервис предоставляют - https://www.pochta.ru/business/adressapi ), но, оценив трудозатраты - прибегли к помощи стороннего сервиса (https://dadata.ru/) - купили доступ к API, доработали систему документооборота и проверили все адреса гораздо быстрее.
И ручной труд остался только для тех адресов, где обнаружились проблемы (подъем первичных документов, уточнение адреса непосредственно у клиента).
решал подобную задачу через гео-апи Яндекса (раньше в день было 10к бесплатных запросов, как сейчас - не знаю), в ответе приходит скорректированный адрес + точность распознавания (точный, до улицы, населенный пункт, не распознан)
так же были какие-то бесплатные geo-api, но там наполненность данных по РФ сильно ниже
PS. у вас данные на вход нормальные, для Яндекса кварталы и ул. чистить не надо, а я чистил откровенный мусор наподобие "пом.1-4, 24, 25, 26, 29" (помещение), "кв. 1э" (квартира) и тд. который принимался за номер дома/строение
Адреса - в сельской местности, может не быть вообще на карте этих адресов
В ФИАС есть практически всё, за исключением адресов типа:
"Нижегородская обл., г. Нижний Новгород, Московский район, 200 м. к северо-западу от пересечения ул. Рябцева с Московским шоссе, около ГРС"
"Республика Саха (Якутия), Нерюнгринский район, п. Чульман, 580 метров на северо-запад от пересечения ул. Транспортная и автомобильной дороги А360 «Лена» Невер-Якутск" :)
у меня были адреса аптек по всей РФ, даже в сельской местности они почти всегда были, процент ненахода (где адрес только населённый пункт - условно "посёлок Заброшенный") сейчас уже оценить не смогу, но он был крайне мал, на 20к+ адресов адресов без улицы\дома (только населённый пункт) было меньше 100, т.е. приблизительно 0.5%
PS/ были адреса только населённый пункт + улица, количество не помню, пусть будет штук 200, довольно много было без точного корпуса (не "д. 14к2", а просто "д. 14"), ориентировочно штук 500 - итого примерно 0.5% + 1% + 2.5% = 4% без точного адреса
Не силен в регулярках и не совсем понял код функции clean_address
.
Почему не все замены напрямую записаны в replacements
, а выполнены отдельно в блоках
# Удаление текста в скобках
и
# Удаление лишних символов, но с сохранением структуры
?
Просто для красоты или там есть какие-то подводные камни не видные с наскока чайнику?
Вместо fuzzywuzzy
уже пора использовать RapidFuzz наверно)
Мне понравилось работать с fuzzywuzzy, но в моем случае этого было недостаточно, в реальных кейсах в ход идут все описанные методы и остаётся ещё на ручной разбор. Казалось бы тривиальная задача, просто разные стили и порядок записи, но это не так, сокращения и опечатки неизбежное адское зло. Так например "Бульвар" может быть записано как "б.", "б-р", "б-вар", "бульв", "бул". А всякие там проезды, проспекты могут быть указаны просто как "пр." и при этом в городе может быть как проспект так и проезд с одинаковым наименованием.
Тут уже написали про dadata, у них отлично всё решено уже, и есть бесплатный план, довольно щедрый. Сам решал такие задачи через них, в том числе и по Пермскому краю (привет землякам).
Python и нечеткое сопоставление: решение проблемы разнобоя в адресах