Привет, Хабр! В своей первой статье про анализ вакансий C#/.Net разработчиков на рынке я выделила очень интересное замечание, которое определило тему сегодняшней статьи – «не количество навыков делает из мидла синьора, а образ его мышления». Построить граф связности компетенций для синьора это конечно хорошо, но к сожалению, на практике применить его достаточно сложно.
Сделав упор на навыки в своем исследовании, я получила зашумленный датасет, не поддающийся адекватной кластеризации. Так что пришло время попытаться пересмотреть подход к использованию полученных данных и попытаться вычленить из них тот качественный скачок, который отделит мидла от синьора.
Имеющиеся проблемы
Для начала стоит понять, какие параметры мы имеем и что нам с этим делать. Мало того, что только 28% вакансий из моего датасета имеют разметку грейда от HR, так еще и корреляция числовых признаков достаточно низкая.
Стоит обратить внимание, что уровень ответственности, выделенный LLM, растет вместе с годами опыта. С одной стороны это достаточно очевидно, а с другой стороны ломает все исследование: пытаясь структурировать данные мы получаем линейную зависимость ответственности от года опыта при нелинейном распределении навыков.
Все что мы сейчас имеем – матрицу компетенций, приведенной в виде ландшафта компетенций в первой статье, которая показывает частоту встречаемости навыка в вакансии конкретного года опыта и невозможность классификации и кластеризации из-за сильной зашумленности данных.
Новая система координат и повторная кластеризация
Технически, мы имеем вес каждого технического навыка для каждого года опыта, представленных в матрице компетенций, флаг наличия архитектурных навыков и уровень ответственности, выявленный LLM при анализе текста вакансии. Используя эти три параметра, мы можем определить новый параметр — Topological Seniority Index (TSI). Он позволит связать между собой все параметры по формуле:
Выглядит страшно, но суть проста: мы повышаем в два раза уровень ответственности Lr, так как он крайне важен при выделении качественного скачка мышления, а сумму частоты встречаемости технических навыков удвоим, если мы имеем и архитектурные навыки (бинарный параметр Ba). Так мы разделяем вакансии с простыми техническими требованиями и вакансиями, где внимание уделяется архитектуре и ответственности за проект.
Необходимость перехода от простого перечисления навыков к использованию их весов достаточно просто объяснить, визуализировав отношение суммарного веса компетенций к их количеству.
Теперь мы имеем параметр, который, теоретически, способен выразить через числовое значение ту самую топологию знаний, которую невозможно было уловить до этого.
Повторная кластеризация радует нас тремя вполне обособленными группами с достаточно приятным индексом силуэта в 0.4.
С одной стороны, замечательно, мы получили разметку, способную каждой вакансии присвоить «рыночный» грейд. Но будем ли мы способны классифицировать наши вакансии по данной разметке?
От кластеров к классификации. Граничные значения грейдов
Проверить стабильность и предсказуемость наших данных было решено с помощью Bagging с использованием kNN. Таким изощренным образом мы сможем сгладить «шум», мешающий классификации и попытаться повысить точность модели. И результаты превзошли все ожидания.
Крайне высокое значение Accuracy вызвано не переобучением, что было проверено на других, незнакомых модели, датасетах.
Но теперь наблюдается другая проблема: пороги перехода между грейдами плавают, в зависимости от выбранного датасета. На графиках, представленных ниже зеленая область — это TSI характерный для Junior, синяя область — для Middle, оранжевая — для Senior.
При этом пики каждого грейда примерно совпадают. Соответственно границы TSI — это относительный показатель. Внутри любой выборки метрика безошибочно ранжирует грейды, но абсолютные значения порогов должны пересчитываться при каждом крупном обновлении данных. Но цель была достигнута – получена метрика, способная более или менее однозначно определить рыночный грейд, используя только числовые данные вакансий.
Выводы
Несмотря на долгий путь и ряд нюансов, мне удалось вывести работающую формулу, которая позволяет отсечь HR-шум и увидеть реальный «вес» вакансии через призму ответственности и сложности. Благодаря этому мы можем предположить, что грейд — это не абстракция, а вполне измеримая величина.
Но все эти смелые заявления работают только при некоторых оговорках:
-
Динамика обучающей выборки: Индекс TSI не является константой. Это «снимок» рыночных ожиданий в конкретный момент времени, требующий регулярной перекалибровки порогов при изменении трендов индустрии.
-
Декларативность данных: Модель анализирует «wish list» работодателей, а не реальные компетенции сотрудников. Это оценка позиционирования грейда рынком, а не финальный вердикт (именно поэтому я провожу так же анализ исходного кода).
-
Доменная специфика: Текущие веса оптимизированы под экосистему C#/.NET. Перенос модели на другие языки (Python, Go) потребует адаптации «архитектурного множителя» под специфику их парадигм.
Поделитесь своим мнением: что вы думаете о таком подходе? Можно ли усмирить хаос и бардак в требованиях на рынке или это босс высшего уровня?
ссылка на оригинал статьи https://habr.com/ru/articles/1026186/