LogoИсмаил Каранкин — Software Engineer, Data, ML
О проекте/

Матчинг компаний по названию используя готовые решения на Python

Что такое матчинг

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

Как происходит идентификация названия на примере

Давайте возьмем для эксперимента компанию Apple и представим уже готовый источник данных с разными наименованиями этой компании. Тогда, если у нас будут встречаться такие названия, как "Эпл", "AAPL", "Apple Inc", мы должны определить их как одну компанию путем сравнения их строковых единиц. Стоит учесть, что в реальной ситуации компании могут иметь куда более сложные варианты написания и больше вариативности, чем в приведенном выше примере. В таких случаях используются более продвинутые матчинг-алгоритмы, соответствующие определенным требованиям.

Методы матчинга

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

Строковой алгоритмИспользуется в сравнение строковых строкАлгоритм на основе машинного обученияИспользуется при необходимости учесть множество разных факторов или данных.

Трудности матчинга

​Основная трудность любого матчинга, это поиск и обработка данных. Добыча данных это целая отдельная область, имеющая ряды уникальностей. Одна из проблем с которой мы можем столкнуться при матчинге названий компаний, это:

Опечатки в названии компанииДанные были взяты с разных источников, та имеют несогласованность, или же устаревшие названия компанийИзменения реальных данных компаний со временемНеоднозначность имен компаний и расплывчатость

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

Генерация данных

Сначала необходимо сгенерировать тестовые данные. Генерировать будем в 2 txt файла. В коде сначала импортируются необходимые библиотеки: pandas для работы с данными, а также random и string для генерации случайных названий. Затем определена функция generate_company_name, которая создает случайные названия компаний. Каждое слово формируется из случайного количества букв (от 5 до 10). Полученные данные сохраняются в два файла (companies_a.txt и companies_b.txt).

Image

Очистка данных и приведение в порядок

Для начала данные необходимо очистить и привести в порядок, убрать пробелы по краям, использовать «lower» для приведение к нижнему регистру. Так же можно автоматически исправить опечатки. Использую библиотеку pandas.

pandas это высокоуровневая Python библиотека для анализа данных. Построена она поверх более низкоуровневой библиотеки NumPy (написана на Си), что является большим плюсом в производительности.

Image

Можно удалить знаки препинания из названий компаний, чтобы сделать текст более чистым и унифицированным.

Image

Удалить ненужные цифры.

Image

Так же применить лемматизацию и стемминг

Image

Реализация метода Jaro-Winkler

Jaro Similarity тоже неплохой метод для решения поставленой задачи. Значение расстояния Jaro варьируется от 0 до 1, где 1 означает, что строки равны, а 0 - отсутствие сходства между двумя строками.

Например:

Image

Пример реализации Jaro-Winkler следующий:

Пример данных в датасетах.

Image

Сначала импортируем нужные библиотеки.

Image

Приводим названия компаний к единообразному виду (к нижнему регистру).

Image

Создаем матрицу схожести и DataFrame для каждой пары компаний.

Image

Выводим результат.

Image

Если реализовать метод jaro_winkler вручную, код будет выглядеть следующим образом:

Если строки равны.

Image

После этого подсчитываем совпадения.

Image

Если совпадений нету.

Image

После этого подсчитываем количество транспозиций и возвращаем коефициент Jaro Similarity.

Image

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

Реализация Cosine Similarity

Cosine similarity это метрика которая измеряет угол между двумя векторами в данных (в нашем случае это текстовая информация, названия компаний). Cosine similarity оценивает сходство между этими векторами, вычисляя косинус угла, который они образуют каком то пространстве.

Если cosine similarity равняеться 1 это означает максимальное сходство векторов, в то время как 0 указывает на отсутствие сходства.

Реализация в Python выглядит следующим образом (данные всё те же):

Импоритуем библиотеки.

Image

Для простоты объединяем оба фрейма данных в один фрейм данных

Image

Обрабатываем текстовые данные.

Image

Выводим баллы сходства для каждой пары компаний.

Image

Cosine similarity выгодно для сравнения текстовых данных, поскольку оно измеряет косинус угла между векторами, что делает его нечувствительным к длине вектора. Но Cosine similarity так же не учитывает порядок слов и все измерения рассматриваются как одинаково важные.

Реализация расстояния Ливанштейна

Расстояние Левенштейна — метрика cходства между двумя строковыми последовательностями. Чем больше расстояние, тем более различны строки. Для двух одинаковых последовательностей расстояние равно нулю.

Например между словами «ключ» и «клюв» расстояние Ливанштейна = 1. Так как потребуется провести замену одной лишь буквы.

Пример реализации на Python без посторонних библиотек:

Сначала инициализируем матрицу расстояний и первый столбец и строку матрицы.

Image

Потом заполняем матрицу, выводим расстояние.

Image

Пример:

Image

Стоит учитывать что метод расстояний Левенштейна чувствителен к длине строк.

Вывод

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

Предсказание стоимости грузоперевозок по Казахстану используя машинное обучение

Вступление.

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

Этапы построения модели предсказания стоимости перевозки грузов:

1. Выбор значимых параметров (feature engineering);

2. Фильтрация и обработка данных;

3. Подготовка данных к обучению;

4. Выбор модели для обучения;

5. Оценка результатов модели.

1. Выбор значимых параметров.

Исходный датасет содержит примерно 24,5 тысячи строк со следующими параметрами:

- Город отправления (0)

- Город прибытия (1)

- Описание груза (2)

- Тип кузова, необходимый для перевозки этого груза (3)

- Расстояние (в километрах) между городом отправления и городом прибытия (4)

- Масса груза (5)

- Единица измерения массы груза (6)

- Объём груза (7)

- Единица измерения объёма груза (8)

- Итоговая стоимость перевозки груза в казахских тенге (9)

- Комментарий к заказу (10)

- Сайт, на котором была получена итоговая стоимость перевозки (11)

На скриншоте приведён фрагмент датасета:

Image

В результате исследования датасета оказалось, что:

- Описание груза (2) может принимать более 5 тысяч различных значений, поэтому этот параметр не является информативным;

- Единица измерения массы груза (6) практически всегда

- тонны (за исключением нескольких опечаток), поэтому также не влияет на предсказание;

- Единица измерения объёма груза (8)

- всегда метры кубические, поэтому этот столбец также лишний;

- Комментарий к заказу (10) может принимать почти 4 тысячи различных значений, поэтому, наряду с описанием груза, не выглядит полезным для модели;

- Сайт (11) в 95% случаев - fafa.kz, так что этот параметр также не нужен.

Таким образом, после “выкидывания” параметров 2, 6, 8, 10 и 11, фрагмент приобретает следующий вид:

Image

2. Фильтрация и обработка данных

Сначала сделаем фильтрацию

- Возможных пунктов отправления (0) и прибытия (1) - несколько сотен, однако топ-20 наиболее частых из них формируют более 90% пунктов отправления и более 80% пунктов прибытия. Таким образом, имеет смысл оставить названия лишь для топ-20 из них, а все остальные обозначить одним и тем же словом (например, “Другой”).

- Возможных типов кузова (3) - пара десятков, но топ-5 из них формируют более 95% записей. Поэтому оставляем названия для топ-5, а остальные обозначаем как “Другой”.

- Максимальное расстояние, встречающееся в датасете - более 6 тысяч километров, что выглядит неправдоподобно, особенно если учесть, что следующее максимальное значение - меньше 3700 км. Поэтому мы просто ограничили расстояние значением 3700 км.

- С объёмом и массой таких проблем не видно - данные выглядят правдоподобно.

- Что касается цены, там явно есть опечатки в данных. В самом деле, медианное значение цены - 200 тысяч тенге, при этом цена выше 2 миллионов тенге встречается в 17 записях, что выглядит неадекватным. Поэтому цена была ограничена значением 2 миллиона тенге.

После фильтрации данные выглядят примерно так:

Image

Однако, чтобы на данных можно было обучать модель, их нужно обработать - превратить категориальные параметры (city_from_new, city_to_new, type_new) в числовые, а числовые (dist_new, volume_new, weight_new, price_new) - нормализовать, чтобы единица измерения не влияла на значимость параметра в модели.

Для конвертации категориальных переменных в числовые проще всего использовать технику one hot encoding - каждому из возможных значений параметра ставится в соответствие число 1, если в данной записи значение параметра совпадает с данным, и 0 в противном случае. Так, например, для параметра city_from_new будет создан 21 столбец - двадцать для топ-20 городов и один для всех оставшихся - и ровно одно из этих 21 значений будет равно 1, а остальные нули. Аналогично, для city_to_new будет создан также 21 числовой столбец, а для type_new - 6 столбцов.

Для нормализации же числовых переменных проще всего отмасштабировать их от 0 до 1: минимальное значение параметра по всем записям будет равно нулю, максимальное - единице, а остальные изменятся пропорционально.

В результате этих манипуляций данные примут следующий вид:

Image

3. Подготовка данных к обучению.

Теперь, когда все данные - числовые, осталось лишь выделить параметр, который мы хотим предсказать (а именно - price_new), а также разбить данные на обучающую и тестовую выборку. Разбиение рекомендуется делать псевдослучайным образом, но с фиксированным порождающим элементом (seed), чтобы при повторных запусках кода разбиение не менялось. При этом рекомендуется, чтобы обучающая выборка была больше тестовой по меньшей мере в несколько раз (для данной задачи была выбрана пропорция 4:1).

В итоге данные принимают вид, указанный на следующем скриншоте:

Image

4. Выбор модели для обучения

Итак, наши данные полностью готовы к обучению, в обучающей выборке примерно 20 тысяч записей, каждая из которых содержит 51 параметр. Также есть основания предполагать, что зависимость цены от числовых параметров (расстояние, масса, объём груза) близка к линейной. Кроме того, легко интерпретируемую модель может применять на практике значительно бОльшее количество людей (таких как перевозчики и бизнесмены), чем трудно интерпретируемую. Поэтому было принято решение остановиться на модели множественной линейной регрессии - простой, но достаточно эффективной при данных условиях. Сначала была опробована простейшая модель с параметрами по умолчанию. Однако она давала слишком большие коэффициенты при параметрах, иногда превосходившие по модулю триллион:

Image

Это явно не способствовало её интерпретируемости, поэтому было принято решение модифицировать модель, “штрафуя” её за слишком большие коэффициенты, то есть применив регуляризацию. Параметр регуляризации alpha был принят равным 0,5 - именно при таком значении коэффициенты при всех параметрах модели стали примерно одного порядка:

Image

Такую модель интерпретировать уже значительно проще, поэтому было решено оставить именно её.

5. Оценка результатов модели.

Поскольку это модель регрессии, а не классификации, результатом оценки модели является не её точность, а коэффициент детерминации R - показатель того, насколько вектор предсказанных значений сонаправлен с вектором реальных значений. Коэффициент R может принимать значения от -1 (абсолютная разнонаправленность - чем больше предсказанное значение, тем меньше реальное) до 1 (абсолютная сонаправленность). При этом R=0 соответствует случайному гаданию, то есть любая модель, для которой R>0, лучше случайной.

Для данной модели получили значение R от 0,459 на обучающей выборке до 0,476 на тестовой:

Image

Заключение

Таким образом, рассмотренная модель достаточно хороша, однако есть пространство для её дальнейшего улучшения. Вот некоторые рекомендации, которые могут помочь это сделать:

1. Корректировка исходного датасета: если исправить опечатки в данных о расстоянии и особенно цене, модель будет работать лучше.

2. Фильтрация выбросов: можно исследовать исходный датасет и понять, какие данные выглядят неадекватно (например, 3 тысячи километров - это больше, чем расстояние между крайними западной и восточной точками Казахстана, так что подобные значения выглядят подозрительно).

3. Добавление описания груза в качестве параметра модели. Это уже более сложная задача, так как для этого нужно будет сделать хорошую категоризацию типов грузов и уметь определять по описанию, к какой категории какой груз относится.

4. Переход к мультипликативной модели регрессии, в которой будет предполагаться, что цена пропорциональна произведению расстояния и массы груза либо произведению расстояния и объёма груза.

5. Переход к более сложной модели (например, нейросети или случайному лесу).