Всем привет!


23-24 ноября в Digital October проходил хакатон по анализу данных в HR-сфере, в котором победила команда выпускников нашей программы "Специалист по большим данным". Кирилл Данилюк, Игорь Парфенов, Егор Андреев и Александр Иваночкин делятся своим решением и впечатлениями от участия.



Контекст


23-24 ноября в Digital October проходил хакатон по анализу данных в HR-сфере — мы организовались в команду (ai.at.work) и решили проникнуться задачами в области HR. Никто из нас до этого на хакатоны не ходил, поэтому интерес был двойной.


Пост получился длинный, поэтому давайте не будем отвлекаться на лишние детали и сразу перейдём к делу :) В соревновании, мы, кстати победили. Итак, нам предложили следующую ситуацию: дана компания «Чайникофф», продающая бытовую технику. «Чайникофф» — крупная розничная сеть, присутствующая во многих регионах, имеет более 190 розничных магазинов. Компания известная, работает на рынке давно (более 20 лет), у неё более 2000 сотрудников и развитая система обучения персонала. Компания проводит как очное обучение сотрудников, так и онлайновое: у неё есть корпоративный портал с библиотекой, тестами для самопроверки и вебинарами.


Очевидно, что одно из конкурентных преимуществ компании — это квалифицированные и замотивированные на развитие сотрудники, в том числе продавцы в розничных магазинах. Поэтому перед нами поставили две задачи:


  1. С учётом имеющихся данных, найти оптимальный способ обучения сотрудников.
  2. Найти какие-то интересные паттерны в данных, т.е., просто «намайнить» что-нибудь полезное из датасета.

Данные


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


«Датасет», предоставленный нам, — это просто два Excel-файла, в каждом из которых — около десятка вкладок, описывающих анкетные данные сотрудников, пройдённые ими курсы, их успешность с точки зрения продаж и выполнения плана, данные опросов сотрудников и т.д. Основная характеристика исходных данных — их низкое качество. Для участников соревнований на Kaggle ситуация непривычная: нет какой-либо предобработки данных, качество исходных таблиц низкое, иногда за гранью. Мы получили данные со всеми возможными проблемами с качеством:


  • Данные в одной колонке могли быть разных типов: числа, текст, пустые значения.
  • Высокая разреженность некоторых таблиц, когда большая часть значений отсутствует.
  • Явные дубликаты в анкетных данных, когда ключи записей различаются, но сами записи идентичны. Например, может быть несколько анкетных записей одного и того же охранника с разными ключами user_id.
  • Структурные проблемы: в одной из таблиц часть колонок располагалась со смещением, в другой (результаты опроса сотрудников) значения располагались то вертикально, то горизонтально.
  • Концептуальные проблемы: результаты с первым опросом сотрудников мы посчитали некорректными, поскольку опрос не был анонимизирован.

Однако не нужно бояться таких «грязных» и зашумлённых данных, надо с ними работать, препроцессить, трансформировать. Главная задача, которую мы себе поставили (и которая заняла большую часть времени хакатона) — это собрать настоящий датасет из того, что у нас есть, и использовать его для дальнейшей работы. Собственно, в этом и проявилось наше преимущество перед другими командами. Когда появляются качественные и грамотно агрегированные данные, дальнейший их анализ становится намного проще.


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


В итоге, мы собрали два датасета:


  • Employees (сотрудники). Набор фич, описывающих сотрудника: возраст, пол, должность, рабочий стаж, общая удовлетворённость работой, выполнение плана продаж, количество пройденных курсов, средний балл за пройденные курсы и другие подобные фичи.
  • Courses (курсы, вебинары, документы из библиотеки). Все те объекты, которые описывают обучение сотрудника в компании. Этот датасет — просто пары сотрудник-курс с дополнительными уточнениями: какую оценку за курс сотрудник получил, сколько времени на курс потратил и т.д.

Решение задачи #1


Мы подошли к проблеме (подобрать оптимальный способ обучения каждого сотрудника) с практической стороны: наше решение должно использовать уже имеющиеся материалы, работать в масштабах всей компании (применяться не только для продавцов) и не требовать ручного программирования категорий.


Очевидно, что ко всему сказанному хорошо подходит рекомендательная система на базе коллаборативной фильтрации — её прототип мы и реализовали. Такие системы сейчас повсеместны, ничего нового мы не сделали, однако собрать её на имеющихся данных было интересно.


Вся обработка данных велась стандартными инструментами Python: Jupyter, numpy, pandas, sklearn. Несколько важных, хотя и очевидных, вещей:


  • Работа с Excel-таблицами осуществлялась через xlrd, хотя, конечно, ничто не мешало нам воспользоваться стандартным импортом Excel из pandas: pandas.read_excel .
  • One-hot encoding должностей. Мы представили должность сотрудника в виде вектора длиной в число уникальных должностей. Все значения этого вектора — нули, кроме одной единицы напротив его должности. Соответственно, кодируя должности всех сотрудников, мы получаем разреженную матрицу размерности M x N, где M — это число уникальных должностей, а N — количество сотрудников.
  • Нормализация непрерывных значений. В sklearn.preprocessing есть класс MinMaxScaler, позволяющий привести наши значения в нужный диапазон, по умолчанию в диапазон [0, 1]. В итоге мы получили 173 признака, каждый из которых (в том числе, one-hot encoded) может иметь значение в интервале от нуля до единицы.


Следующая задача — определение меры похожести разных сотрудников друг с другом. Схожим сотрудникам мы рекомендуем схожие курсы. В терминах рекомендательных систем, это коллаборативная фильтрация User-User. Самый простой способ — использовать косинусную меру. Мы представляем каждого сотрудника как вектор в 173-мерном пространстве и попарно для каждых двух сотрудников считаем косинус угла между векторами:



Фактически, зная скалярное произведение и норму векторов, мы можем посчитать, насколько два сотрудника «похожи». В рамках sklearn это делается в одну строчку:


sklearn.metrics.pairwise.cosine_similarity(df_profiles.iloc[:,1:])


Мы получаем матрицу размерностью N x N, где N — число сотрудников. Каждое значение в матрице — мера сходства двух сотрудников. Нам хотелось добавить нелинейности к этой мере, чтобы сильнее подчеркнуть сходство или различие двух сотрудников:


def norm_cos(x):
 if x < 0.25: return x / 10
 if x < 0.5: return x / 5
 if x < 0.75: return x / 2
 return x

Дальше мы взялись за датасет с курсами. Фактически, требовалось сделать нормализацию оценок курсов с помощью базовых предикторов сотрудников (users) и курсов (items). «Оценка» курса — это просто сумма числа раз, которые каждый сотрудник прошёл данный курс (или вебинар, или просмотрел электронный документ на портале). Посчитав базовые предикторы, мы можем убрать смещение оценки. Например, если один сотрудник проходит много курсов, его оценка будет доминировать и сильно искажать рекомендации. Такие искажения хорошо выявляются и снижаются базовыми предикторами.


Получив две матрицы: матрицу сходства сотрудников и нормализованную базовыми предикторами матрицу оценок курсов, мы можем их перемножить и, таким образом, получить оценку каждого курса (item) для каждого сотрудника (user). Для рекомендации курсов, мы можем взять нужное количество курсов с самыми высокими оценками:



Как мы видим, рекомендаций курсов для кладовщика у нас, фактически, нет. Зато для управляющего мы можем что-то посоветовать.


Решение задачи #2


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


Мы решили использовать технику снижения размерности на основе метода главных компонент (PCA), оставив две компоненты. Такие результаты PCA легче визуализировать и их можно показать руководству.


После трансформации, мы кластеризовали результаты PCA с помощью K-Means. Число кластеров подбирали с помощью среднего silhouette score кластеров. Чем выше данный показатель, тем лучше кластеры отделимы друг от друга.



K-Means выделил 10 кластеров в этом датасете. Как видим, кластер #3 располагается дальше всех других и чётко отделим от других — поэтому его silhouette score выше других. Красная вертикальная линия на левой диаграмме — средний показатель.


Что нам даёт такая кластеризация? Оказалось, что наша кластеризация получилась фактически по должностям и «немного чего-то ещё». Например, кластер #0 — это по большей части продавцы-кассиры, а кластер #5 — старшие продавцы-кассиры. Но иногда в кластере #5 мы видим и простых кассиров.


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




Вместо заключения


Какие выводы лично мы сделали после хакатона?


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


Во-вторых, мы не изобрели ничего нового. PCA, K-Means, item-item, user-user коллаборативная фильтрация — все эти техники давно известны. PCA и K-Means работают практически «из коробки» в sklearn. Однако, если наложить их на конкретную задачу, они способны удивить людей, которые до этого ничего подобного не видели.


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

Поделиться с друзьями
-->

Комментарии (0)