Кто сможет раскритиковать/улучшить алгоритм распознавания прайс-листа?
Есть поставщики с разными форматами прайсов (какие колонки есть, каких нет, названия колонок). Более того, форматы прайсов у одного поставщика постоянно меняются, поэтому необходимо написать функцию, которая сама будет определять, что содержится в данной колонке прайса.
Возможны следующие колонки: артикул, код, штрихкод, наименование, остаток, гарантия, цена опт, цена мелкоопт, цена розничная. Значение в какой-то ячейке может отсутствовать.
Предлагаю следующий алгоритм:
1. Определить колонки в которых есть данные, так как есть пустые колонки.
2. Сделать запрос в БД - поиск значений из первых 50 строк прайса в каждом поле. Где результат будет близок к 100 % - там нужное поле.
3. Останутся колонки с ценами и остатком, для определения, что в них, использовать следующие фильтры, по которым определить, где цена, а где - остаток:
1) количество - это не цифра, а примерное обозначение <5, ** и т.д.
2) цена, как правило, содержит валюту
3) если у нас остается, например, 4 колонки, то можно найти, значения в каких колонках связаны, а в каких - нет
4) если колонки 2 - количество - меньшая.
А нельзя ли сделать ООПешненько и подставлять нужный ридер под нужного поставщика? вот с этим бешеным поставщиком который переделывает прайс постоянно будет морока конечно, но он один такой. вообще какие-то отличительные особенности каждого конкретного прайса есть? ну там может определенный префикс перед каждым номером айтема прайса или еще что?
Алексей Кулаков: Они все этим отличаются... Сейчас у меня жестко забито в каком прайсе что в какой колонке должно быть, но перед этим проверяется по заголовкам, и не зря. Каждый день то колонка пропадает, то заголовков нет, то названия колонок меняются и т.д. Но менять постоянно настройки, учитывая, что прайсы полностью автоматически обрабатываются, тоже не вариант.
По артикулу - да, есть поставщики, у которых он одной длины, но есть те, у которых они разной длины.
не повезло вам. тут все обработать сложно. могут быть конфликты, кто знает что взбредет в голову поставщика в этот раз? какое-то участие пользователя для разрешения конфликтов предусматривается?
Слишком много сайд еффектов придется обработать
Те слишком дорогая получится автоматизация
Если у тебя сервис по парсингу прайс-листов, то оно того стоит
Тебе же проще ввести понятие пресета, те привязки номера колонки к типу данных.
Показываешь пользователю 20 рандомных строк из файла
Он выбирает пресет
Дальше ты процессиш
Если поместить все в транзакцию БД с роллбеком, то даже данные не попортишь
Если обьем такой работы буде увеличиваться, то ты можешь начать собирать статистику
прайс - данные - куда попала строка из прайса в бд
И вот тут уже можно будет подумать про модные технологии
Если это эксель - проще потратить 3 минуты и перетусовать колонки вручную. Выделить всю колонку и перетащить мышой - 5 сек. Да, это обезьянья работа, но это проще чем потом чистить базу от ошибочного прсинга. На крайняк загружать в админке колонки(скажем первые 10 значений из прайса) и селектами расставить что есть что.
Для автомата(если уж решили писать) проще будет использовать регулярки чем сравнение с базой. Например артикул всегда определенной длинны? Или штрихкод? Цена имеет 2 знака после запятой? Название начинается с букв обычно, и содержит только буквы, цифры и пробельные символы? Кароче определить уникальность поля и использовать в регулярке.
У меня все автоматом идет, просто жестко забито - у такого поставщика - такие колонки, если названию отличаются или колонки нет, то просто не парсится.
Про регулярки - согласен. А как их применять к массиву? К каждому элементу в колонке, а потом сравнивать процент соответствия по всем?
Что если не привязываться к порядку колонок, а выводить прайс как есть в эксельке. Соответственно в базу пишем не каждую колонку/ячейку отдельно, а всю таблицу в виде серрииализованного массива.
Может при загрузке показать загруженную таблицу, над столбиками сделать выпадающий список, который позволит расставить порядок столбцов. После сохранить изменения.
я вижу вариант как обработки шапки прайса и определение расположения колонок по сравнению с текущей конфигурацией разметки, то есть если в конфиге указано что 2 колонка артикул, то новый прайс от поставщика ты проверяешь 2 колонку а конкретно шапку на наличие вариантов article,code,артикул, код и т.д. если не соответствует то выводить сообщение для ручной перенастройки разметки.
Если шапки нет то только анализ первый 100-200 строк на ожидаемые данные с помощью регулярок, но тут как то все не стабильно, но другого варианта не вижу.
Если еще актуально. Загружаю в pandas, затем передаю "распознавателю колонок" (ищет заголовки в первых n строках (по количеству совпадений ключевых слов) и переименовывает их в принятые в программе имена (для возможности слияния нескольких документов от разных поставщиков), сообщает о колонках которых нет в словаре (ConfigParser), если критично - дополняю конфиг новыми подписями).
В зависимости от набора колонок к каждой применяются методы обработки (валидация, конвертирование к единому формату).
Результат обработки, ошибки, предупреждения, лог накапливаются в экземпляре датакласса. Для слияния, анализа, выборки, построения графиков - все загружаю в синглтон, а потом - pythondocx, matplotlib, pyqt, экспорт по фильтрам в Excel...
Хотел попробовать прикрутить машинное обучение по распознаванию колонок, но в интернетах ничего похожего не нашел и опыта не имею(((. Предполагал, что веса можно выставить по косвенным признакам (уникальных значений в колонке, количество символов, типы, совпадение по словарю, относительная позиция и т.д.). Если у кого-то будут идеи или направления гугления, буду благодарен.