Содержание¶
I. Постановка задачи и план исследования
II. Формирование базы данных
III. Предобработка и очистка данных
IV. Исследовательский анализ данных (EDA)
- Блок 1. Общий обзор рынка
- Блок 2. Деньги и прозрачность
4. Прозрачность условий: Где чаще указывают зарплату
5. География зарплат: Расчет средней и медианной зарплаты
6. Карьерный рост: Зависимость дохода от опыта - Блок 3. Условия работы
7. Формат и гибкость: Типы занятости и графики
8. Связь между опытом и доступностью удаленной занятости - Блок 4. Навыки и бонус
9. Профиль компетенций: Сравнение частоты Hard Skills
10. [Bonus Insight] Тайминг публикаций: Активность по дням недели
I. Постановка задачи и план исследования¶
В рамках данного проекта проведено исследование рынка вакансий по направлениям «Аналитик данных» и «Системный аналитик» (включая англоязычные аналоги запросов).
Цель исследования: Сформировать объективный обзор рынка для сравнения условий оплаты труда, графиков работы и требований к ключевым навыкам в разрезе двух специальностей.
Ход работы:¶
- Сбор данных: Самостоятельное извлечение актуальных вакансий напрямую через API HH.ru.
- Обработка: Очистка сырых данных, работа с дубликатами и создание структурированной базы для анализа.
- Анализ и визуализация:
- Общий обзор рынка: объем вакансий и распределение по ролям.
- Деньги и прозрачность: анализ предлагаемых зарплат и частоты их указания.
- Условия работы: сравнение графиков и типов занятости.
- Навыки: выявление технологического ядра и популярных связок инструментов.
↑ Вернуться к содержанию¶
II. Формирование базы данных¶
На данном этапе будет реализован сбор данных с платформы HH.ru.
Технические особенности этапа:
- Инструмент: Написан собственный парсер для взаимодействия с публичным API HeadHunter.
- Область поиска: Вакансии по ключевым запросам «Аналитик данных» и «Системный аналитик» (включая англоязычные вариации).
- Методология: Ввиду лимитов API на выдачу (до 2000 записей на запрос), логика сбора настроена таким образом, чтобы получить максимально широкую и актуальную выборку.
Результатом работы парсера является массив сырых данных, которые далее проходят цикл предобработки для формирования единой базы.
Подготовка окружения и импорт библиотек¶
Для реализации проекта необходимо подготовить рабочую среду. Мы импортируем стандартные библиотеки Python для обработки данных, визуализации и взаимодействия с API.
import requests # Отправка запросов к API HH.ru
import pandas as pd # Основной инструмент для работы с таблицами
import numpy as np # Математические операции и работа с массивами
import re # Регулярные выражения для поиска навыков в тексте
import sys # Для доступа к системным параметрам Python
import matplotlib.pyplot as plt # Базовая визуализация
import seaborn as sns # Улучшенные статистические графики
from IPython.display import display, HTML, clear_output # Для очистки вывода в ячейке
import time # Контроль пауз между запросами к API
# Настройка отображения: выводим все столбцы без ограничений
pd.set_option('display.max_columns', None)
# Проверка рабоспособности и доступа к API и просмотр списка столбцов и выбора необходимых для анализа.
url = 'https://api.hh.ru/vacancies'
# Используем мои данные для авторизации
# Формат: Название_приложения/Версия (email)
user_email = 'fatkulinedik@yandex.ru'
app_name = 'MyDataAnalysisProject'
headers = {
'User-Agent': f'{app_name}/1.0 ({user_email})'
}
params = {
'text': 'Data Analyst', # Возьмем один запрос
'area': 1, # Москва
'per_page': 1 # Возьмем 1 вакансию
}
# Делаем запрос
res = requests.get(url, params=params, headers=headers)
if res.status_code == 200:
df_test = pd.DataFrame(res.json()['items'])
print("Список всех доступных колонок:")
print(list(df_test.columns))
else:
print(f"Статус: {res.status_code}")
print(f"Текст ошибки: {res.text}")
Список всех доступных колонок: ['id', 'premium', 'name', 'department', 'has_test', 'response_letter_required', 'area', 'salary', 'salary_range', 'type', 'address', 'response_url', 'sort_point_distance', 'published_at', 'created_at', 'archived', 'apply_alternate_url', 'branding', 'show_logo_in_search', 'show_contacts', 'insider_interview', 'url', 'alternate_url', 'relations', 'employer', 'snippet', 'contacts', 'schedule', 'working_days', 'working_time_intervals', 'working_time_modes', 'accept_temporary', 'fly_in_fly_out_duration', 'work_format', 'working_hours', 'work_schedule_by_days', 'accept_labor_contract', 'civil_law_contracts', 'night_shifts', 'professional_roles', 'accept_incomplete_resumes', 'experience', 'employment', 'employment_form', 'internship', 'adv_response_url', 'is_adv_vacancy', 'adv_context']
Выбор целевых атрибутов и логика сбора данных¶
Доступ к API успешно проверен. На выходе мы получаем избыточное количество данных, поэтому для анализа различий между специализациями я отобрал только необходимые параметры:
Основные поля вакансии:
id— уникальный номер вакансии (необходим для исключения дубликатов).name— название вакансии.salary— данные о доходе (будут разобраны на составляющие: «от», «до» и «валюта»).area— фактический город размещения.published_at— дата публикации (для оценки актуальности рынка).employer— название компании.experience— требуемый опыт работы (Нет опыта, от 1 до 3 лет и т.д.).schedule— график работы (удаленка, полный день и др.).employment— тип занятости (полная, проектная и т.д.).snippet(полеrequirement) — краткое описание требований, из которого будет извлекаться стек технологий (SQL, Python и т.д.).
Дополнительные расчетные колонки:
target_city— город, по которому ведется поиск.target_query— поисковый запрос (data analyst, аналитик данных и т.д.).
Зачем нужен
target_city? > Хотя в данных естьarea, я создаю дополнительный столбец для фильтрации. HH.ru часто подмешивает в московскую выдачу вакансии из ближайшего пригорода (Одинцово, Химки). Это поле поможет оставить только релевантные данные.Аналогичная логика для
target_query. По запросу Аналитик данных HH.ru выдает похожие названия, как Аналитик хранилищ, Аналитик баз данных и т.д.. Этот столбец поможет в дальнейшем удобнее сгруппировать направление, которое мы будем искать.А также в дальнейшем по ходу предобработки будут созданы дополнительные столбцы для Навыков и Рассчета ЗП.
План реализации¶
Для исследования выбрана тройка наиболее активных IT-хабов: Москва, Санкт-Петербург и Казань.
Ниже представлен скрипт, который собирает информацию по выбранным городам, используя 4 варианта поисковых запросов:
аналитик данныхdata analystсистемный аналитикsystem analyst
На этом этапе мы собираем сырой массив данных, который в дальнейшем будет очищен от лишних записей и приведен к финальному виду.
# Вводные данные
cities = {'Москва': 1, 'Санкт-Петербург': 2, 'Казань': 88}
queries = ['аналитик данных', 'data analyst', 'системный аналитик', 'system analyst']
all_vacancies = [] # Сюда будем складывать всё найденное
print("Начинаю сбор данных...")
for city_name, city_id in cities.items():
for query in queries:
print(f"Парсим: {city_name} | Запрос: {query}")
# Листаем страницы (от 0 до 19, т.к. максимум 2000 вакансий)
for page in range(20):
params = {
'text': query,
'area': city_id,
'per_page': 100, # Максимум вакансий на страницу
'page': page
}
res = requests.get(url, params=params, headers=headers)
if res.status_code != 200:
print(f"Ошибка на странице {page}: {res.status_code}")
break
items = res.json().get('items', [])
# Если вакансии на странице закончились — выходим из цикла страниц
if not items:
break
# Добавляем в каждую вакансию метки города и запроса (для будущего анализа)
for item in items:
item['target_city'] = city_name
item['target_query'] = query
all_vacancies.append(item)
# Маленькая пауза, чтобы HH не забанил (0.2 сек)
time.sleep(0.2)
# Очищаем вывод, чтобы не спамить в Jupyter, и пишем статус
clear_output(wait=True)
print(f"Собрано всего: {len(all_vacancies)} вакансий...")
# Превращаем список в одну таблицу
df_full = pd.DataFrame(all_vacancies)
print("Таблица создана.")
display(df_full.head())
Собрано всего: 8764 вакансий... Таблица создана.
| id | premium | name | department | has_test | response_letter_required | area | salary | salary_range | type | address | response_url | sort_point_distance | published_at | created_at | archived | apply_alternate_url | show_contacts | insider_interview | url | alternate_url | relations | employer | snippet | contacts | schedule | working_days | working_time_intervals | working_time_modes | accept_temporary | fly_in_fly_out_duration | work_format | working_hours | work_schedule_by_days | accept_labor_contract | civil_law_contracts | night_shifts | professional_roles | accept_incomplete_resumes | experience | employment | employment_form | internship | adv_response_url | is_adv_vacancy | adv_context | target_city | target_query | branding | show_logo_in_search | brand_snippet | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 131549046 | False | Аналитик данных | None | False | False | {'id': '1', 'name': 'Москва', 'url': 'https://... | None | None | {'id': 'open', 'name': 'Открытая'} | {'city': 'Москва', 'street': 'Раменский бульва... | None | None | 2026-04-12T16:22:43+0300 | 2026-04-12T16:22:43+0300 | False | https://hh.ru/applicant/vacancy_response?vacan... | False | None | https://api.hh.ru/vacancies/131549046?host=hh.ru | https://hh.ru/vacancy/131549046 | [] | {'id': '11941855', 'name': 'ИКС БИО ТЕХНОЛОДЖИ... | {'requirement': '...к <highlighttext>аналитике... | None | {'id': 'fullDay', 'name': 'Полный день'} | [] | [] | [] | True | [] | [{'id': 'HYBRID', 'name': 'Гибрид'}] | [{'id': 'HOURS_8', 'name': '8 часов'}, {'id': ... | [{'id': 'FIVE_ON_TWO_OFF', 'name': '5/2'}] | True | [{'id': 'SELF_EMPLOYED', 'name': 'с самозаняты... | False | [{'id': '156', 'name': 'BI-аналитик, аналитик ... | False | {'id': 'between3And6', 'name': 'От 3 до 6 лет'} | {'id': 'full', 'name': 'Полная занятость'} | {'id': 'FULL', 'name': 'Полная'} | False | None | False | None | Москва | аналитик данных | NaN | NaN | NaN |
| 1 | 131889061 | False | Аналитик баз данных | None | False | False | {'id': '1', 'name': 'Москва', 'url': 'https://... | {'from': 80000, 'to': 120000, 'currency': 'RUR... | {'from': 80000, 'to': 120000, 'currency': 'RUR... | {'id': 'open', 'name': 'Открытая'} | {'city': 'Москва', 'street': 'Хорошёвское шосс... | None | None | 2026-04-12T20:11:58+0300 | 2026-04-12T20:11:58+0300 | False | https://hh.ru/applicant/vacancy_response?vacan... | False | None | https://api.hh.ru/vacancies/131889061?host=hh.ru | https://hh.ru/vacancy/131889061 | [] | {'id': '1156064', 'name': 'Фортис Технологии',... | {'requirement': 'Навыки работы с СУБД: построе... | None | {'id': 'remote', 'name': 'Удаленная работа'} | [] | [] | [] | False | [] | [{'id': 'ON_SITE', 'name': 'На месте работодат... | [{'id': 'HOURS_8', 'name': '8 часов'}] | [{'id': 'FIVE_ON_TWO_OFF', 'name': '5/2'}] | False | [] | False | [{'id': '156', 'name': 'BI-аналитик, аналитик ... | False | {'id': 'between3And6', 'name': 'От 3 до 6 лет'} | {'id': 'full', 'name': 'Полная занятость'} | {'id': 'FULL', 'name': 'Полная'} | False | None | False | None | Москва | аналитик данных | NaN | NaN | NaN |
| 2 | 131978902 | False | Аналитик данных | None | False | False | {'id': '1', 'name': 'Москва', 'url': 'https://... | {'from': 120000, 'to': 150000, 'currency': 'RU... | {'from': 120000, 'to': 150000, 'currency': 'RU... | {'id': 'open', 'name': 'Открытая'} | {'city': 'Москва', 'street': 'Спартаковский пе... | None | None | 2026-04-12T10:27:56+0300 | 2026-04-12T10:27:56+0300 | False | https://hh.ru/applicant/vacancy_response?vacan... | True | None | https://api.hh.ru/vacancies/131978902?host=hh.ru | https://hh.ru/vacancy/131978902 | [] | {'id': '2630490', 'name': 'Медиабюро Статус пр... | {'requirement': 'Высшее образование. Аналитиче... | None | {'id': 'fullDay', 'name': 'Полный день'} | [] | [] | [] | False | [] | [{'id': 'ON_SITE', 'name': 'На месте работодат... | [{'id': 'HOURS_8', 'name': '8 часов'}] | [{'id': 'FIVE_ON_TWO_OFF', 'name': '5/2'}] | True | [] | False | [{'id': '54', 'name': 'Координатор отдела прод... | False | {'id': 'between1And3', 'name': 'От 1 года до 3... | {'id': 'full', 'name': 'Полная занятость'} | {'id': 'FULL', 'name': 'Полная'} | False | None | False | None | Москва | аналитик данных | NaN | NaN | NaN |
| 3 | 131232738 | False | Аналитик данных | None | False | False | {'id': '1', 'name': 'Москва', 'url': 'https://... | None | None | {'id': 'open', 'name': 'Открытая'} | None | None | None | 2026-04-12T07:11:54+0300 | 2026-04-12T07:11:54+0300 | False | https://hh.ru/applicant/vacancy_response?vacan... | False | None | https://api.hh.ru/vacancies/131232738?host=hh.ru | https://hh.ru/vacancy/131232738 | [] | {'id': '588914', 'name': 'Aviasales.ru', 'url'... | {'requirement': 'Опыт в дата или продуктовой <... | None | {'id': 'remote', 'name': 'Удаленная работа'} | [] | [] | [] | False | [] | [{'id': 'REMOTE', 'name': 'Удалённо'}] | [{'id': 'HOURS_9', 'name': '9 часов'}] | [{'id': 'FIVE_ON_TWO_OFF', 'name': '5/2'}] | False | [] | False | [{'id': '156', 'name': 'BI-аналитик, аналитик ... | False | {'id': 'between3And6', 'name': 'От 3 до 6 лет'} | {'id': 'full', 'name': 'Полная занятость'} | {'id': 'FULL', 'name': 'Полная'} | False | None | False | None | Москва | аналитик данных | NaN | NaN | NaN |
| 4 | 131868762 | False | Аналитик платформы данных | None | False | False | {'id': '1', 'name': 'Москва', 'url': 'https://... | None | None | {'id': 'open', 'name': 'Открытая'} | {'city': 'Москва', 'street': 'Летниковская ули... | None | None | 2026-04-12T12:47:45+0300 | 2026-04-12T12:47:45+0300 | False | https://hh.ru/applicant/vacancy_response?vacan... | True | None | https://api.hh.ru/vacancies/131868762?host=hh.ru | https://hh.ru/vacancy/131868762 | [] | {'id': '11660779', 'name': 'Цифровой аудит', '... | {'requirement': 'Опыт работы в хранилищах <hig... | None | {'id': 'fullDay', 'name': 'Полный день'} | [] | [] | [] | False | [] | [{'id': 'HYBRID', 'name': 'Гибрид'}] | [{'id': 'HOURS_8', 'name': '8 часов'}] | [{'id': 'FIVE_ON_TWO_OFF', 'name': '5/2'}] | True | [] | False | [{'id': '156', 'name': 'BI-аналитик, аналитик ... | False | {'id': 'between3And6', 'name': 'От 3 до 6 лет'} | {'id': 'full', 'name': 'Полная занятость'} | {'id': 'FULL', 'name': 'Полная'} | False | None | False | None | Москва | аналитик данных | NaN | NaN | NaN |
На текущем этапе сформирован первичный датасет df_full с помощью скрипта для парсинга вакансий. Данный массив является сырым и требует этапа предобработки перед началом глубокого анализа.
III. Предобработка и очистка данных¶
Ключевые проблемы исходных данных:
- Наличие дубликатов: Так как поиск велся по пересекающимся запросам на русском и английском языках, в общую выдачу попали идентичные вакансии.
- Сложная структура: Данные в столбце
salaryи других полях требуют распаковки и приведения типов. - Избыточность: Массив содержит большое количество технических колонок, не влияющих на результат исследования.
Первоочередная задача: Очистка датасета от дубликатов по уникальному идентификатору вакансии (id).
# Проверим сколько сейчас вакансий.
print(f"Строки до удаления дубликатов: {len(df_full)}")
# Удаляем дубликаты по ID вакансии
df_full = df_full.drop_duplicates(subset='id')
# Смотрим, сколько стало
print(f"Стало строк после удаления дубликатов: {len(df_full)}")
Строки до удаления дубликатов: 8764 Стало строк после удаления дубликатов: 6177
Оптимизация структуры данных¶
После удаления повторов необходимо привести таблицу к рабочему виду. На этом этапе мы:
- Фильтруем признаки: Оставляем только те колонки, которые необходимы для анализа.
- Распаковываем вложенные структуры: Преобразуем данные из JSON-подобных словарей (словарь в ячейке) в плоский и понятный вид, удобный для манипуляций в Pandas.
# Оставляем только нужные колонки из списка
columns_to_keep = [
'id', 'name', 'area', 'salary', 'experience',
'employment', 'schedule', 'employer', 'snippet', 'published_at',
'target_city', 'target_query'
]
# Создаем новый фрейм данных
df = df_full[columns_to_keep].copy()
# Функция для очистки словарей (если данных нет, пишем None)
def get_name(x):
return x.get('name') if isinstance(x, dict) else None
# Распаковываем простые колонки
df['city'] = df['area'].apply(get_name)
df['company'] = df['employer'].apply(get_name)
df['exp_level'] = df['experience'].apply(get_name)
df['job_type'] = df['employment'].apply(get_name)
df['work_schedule'] = df['schedule'].apply(get_name)
# Распаковываем зарплату (от, до и валюта)
df['salary_from'] = df['salary'].apply(lambda x: x.get('from') if isinstance(x, dict) else None)
df['salary_to'] = df['salary'].apply(lambda x: x.get('to') if isinstance(x, dict) else None)
df['salary_currency'] = df['salary'].apply(lambda x: x.get('currency') if isinstance(x, dict) else None)
# Вытаскиваем требования из snippet
df['requirements'] = df['snippet'].apply(lambda x: x.get('requirement') if isinstance(x, dict) else None)
# Удаляем старые «грязные» колонки, которые мы уже распаковали
df.drop(columns=['area', 'employer', 'experience', 'employment', 'salary', 'snippet', 'schedule'], inplace=True)
display(df.head())
| id | name | published_at | target_city | target_query | city | company | exp_level | job_type | work_schedule | salary_from | salary_to | salary_currency | requirements | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 131549046 | Аналитик данных | 2026-04-12T16:22:43+0300 | Москва | аналитик данных | Москва | ИКС БИО ТЕХНОЛОДЖИ | От 3 до 6 лет | Полная занятость | Полный день | NaN | NaN | None | ...к <highlighttext>аналитике</highlighttext> ... |
| 1 | 131889061 | Аналитик баз данных | 2026-04-12T20:11:58+0300 | Москва | аналитик данных | Москва | Фортис Технологии | От 3 до 6 лет | Полная занятость | Удаленная работа | 80000.0 | 120000.0 | RUR | Навыки работы с СУБД: построение SQL-запросов.... |
| 2 | 131978902 | Аналитик данных | 2026-04-12T10:27:56+0300 | Москва | аналитик данных | Москва | Медиабюро Статус презенс | От 1 года до 3 лет | Полная занятость | Полный день | 120000.0 | 150000.0 | RUR | Высшее образование. Аналитический склад ума, в... |
| 3 | 131232738 | Аналитик данных | 2026-04-12T07:11:54+0300 | Москва | аналитик данных | Москва | Aviasales.ru | От 3 до 6 лет | Полная занятость | Удаленная работа | NaN | NaN | None | Опыт в дата или продуктовой <highlighttext>ана... |
| 4 | 131868762 | Аналитик платформы данных | 2026-04-12T12:47:45+0300 | Москва | аналитик данных | Москва | Цифровой аудит | От 3 до 6 лет | Полная занятость | Полный день | NaN | NaN | None | Опыт работы в хранилищах <highlighttext>данных... |
Текстовая очистка и удаление HTML-тегов¶
На текущем этапе мы сформировали датафрейм с целевыми атрибутами. Однако текстовое поле requirement (требования), полученное из API, содержит избыточную разметку: HTML-теги (например, <highlight>, <li> и др.).
Необходимо очистить текстовые данные от тегов для корректного поиска ключевых навыков и проведения дальнейшего контент-анализа. Для этого мы применим библиотеку re (регулярные выражения).
# Функция для удаления HTML-тегов (<highlight> и прочие)
def clean_tags(text):
if isinstance(text, str):
# Удаляем теги, заменяя их на пустоту
return re.sub(r'<.*?>', '', text)
return text
# Применяем очистку к нашей новой колонке requirements
df['requirements'] = df['requirements'].apply(clean_tags)
# Посмотрим на результат: название вакансии и очищенное требование
display(df[['name', 'requirements']].head())
| name | requirements | |
|---|---|---|
| 0 | Аналитик данных | ...к аналитике и исследованию данных. Продвину... |
| 1 | Аналитик баз данных | Навыки работы с СУБД: построение SQL-запросов.... |
| 2 | Аналитик данных | Высшее образование. Аналитический склад ума, в... |
| 3 | Аналитик данных | Опыт в дата или продуктовой аналитике от трех ... |
| 4 | Аналитик платформы данных | Опыт работы в хранилищах данных (DWH/КХД). Уве... |
Приведение типов: Формат даты¶
Для удобства дальнейшей работы с временными рядами переводим значения столбца published_at из строкового формата в datetime и оптимизируем отображение, оставляя только дату.
# Переводим строку в формат даты
df['published_at'] = pd.to_datetime(df['published_at']).dt.date
# Переименуем колонку для наглядности
df.rename(columns={'published_at': 'published_date'}, inplace=True)
# Проверим, что получилось
display(df.head())
| id | name | published_date | target_city | target_query | city | company | exp_level | job_type | work_schedule | salary_from | salary_to | salary_currency | requirements | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 131549046 | Аналитик данных | 2026-04-12 | Москва | аналитик данных | Москва | ИКС БИО ТЕХНОЛОДЖИ | От 3 до 6 лет | Полная занятость | Полный день | NaN | NaN | None | ...к аналитике и исследованию данных. Продвину... |
| 1 | 131889061 | Аналитик баз данных | 2026-04-12 | Москва | аналитик данных | Москва | Фортис Технологии | От 3 до 6 лет | Полная занятость | Удаленная работа | 80000.0 | 120000.0 | RUR | Навыки работы с СУБД: построение SQL-запросов.... |
| 2 | 131978902 | Аналитик данных | 2026-04-12 | Москва | аналитик данных | Москва | Медиабюро Статус презенс | От 1 года до 3 лет | Полная занятость | Полный день | 120000.0 | 150000.0 | RUR | Высшее образование. Аналитический склад ума, в... |
| 3 | 131232738 | Аналитик данных | 2026-04-12 | Москва | аналитик данных | Москва | Aviasales.ru | От 3 до 6 лет | Полная занятость | Удаленная работа | NaN | NaN | None | Опыт в дата или продуктовой аналитике от трех ... |
| 4 | 131868762 | Аналитик платформы данных | 2026-04-12 | Москва | аналитик данных | Москва | Цифровой аудит | От 3 до 6 лет | Полная занятость | Полный день | NaN | NaN | None | Опыт работы в хранилищах данных (DWH/КХД). Уве... |
Инсайт для соискателя: > Перевод данных в формат
published_date— это не только техническая очистка, но и база для прикладного вывода. Анализ дня недели публикации поможет определить пиковые периоды активности работодателей, чтобы соискатель мог эффективнее мониторить свежие вакансии.
Анализ полноты данных: Поле Salary¶
Важным этапом подготовки данных является оценка пропусков в информации о доходах. Необходимо определить, какой объем вакансий содержит сведения о заработной плате, чтобы оценить репрезентативность будущих выводов о финансовом рынке.
# Считаем количество пропусков по валюте
total_vacancies = len(df)
no_salary_count = df['salary_currency'].isna().sum()
has_salary_count = total_vacancies - no_salary_count
# Считаем проценты
no_salary_pct = (no_salary_count / total_vacancies) * 100
print(f"Общее количество вакансий: {total_vacancies}")
print(f"Вакансий с указанной ЗП: {has_salary_count}")
print(f"Вакансий БЕЗ указания ЗП: {no_salary_count} ({no_salary_pct:.2f}%)")
# Маленькая проверка: есть ли строки, где указана валюта, но нет цифр?
check_logic = df[df['salary_currency'].notna() & df['salary_from'].isna() & df['salary_to'].isna()]
if len(check_logic) > 0:
print(f"Внимание: есть {len(check_logic)} вакансий с валютой, но без сумм.")
Общее количество вакансий: 6177 Вакансий с указанной ЗП: 2137 Вакансий БЕЗ указания ЗП: 4040 (65.40%)
Вывод по результатам проверки:¶
Доля вакансий без указания дохода составляет 65,3%. Это существенный объем, который требует осознанного подхода к дальнейшей обработке:
- Сохранение репрезентативности: Я не удаляю эти строки на текущем этапе. Они содержат критически важную информацию о работодателях и требованиях к кандидатам (стеке технологий), которая необходима для полноты исследования.
- Стратегия анализа ЗП: Поскольку заполнение такого количества пропусков (импутация) может привести к смещению оценок, расчеты среднего и медианного дохода будут проводиться исключительно по подвыборке, где данные о зарплате указаны явно.
- Дальнейшие шаги: В блоке анализа доходов мы сфокусируемся на «прозрачной» части рынка, а также проверим, в каких городах работодатели чаще склонны открыто публиковать финансовые условия.
Группировка поисковых запросов¶
Для корректной визуализации необходимо объединить схожие по смыслу запросы в единые категории. Поиск велся на двух языках (RU/EN), что создало избыточность в названиях позиций.
Что мы делаем:
- Создаем колонку
vacancy_category. - Объединяем запросы («Data Analyst» + «Аналитик данных») и («System Analyst» + «Системный аналитик») в две соответствующие группы.
Это позволит сохранить историю поиска в target_query, но при этом получить чистые и репрезентативные графики без дублирования ролей.
# Создаем словарь для маппинга (замены)
# Ищем ключевые слова в target_query и объединяем их
def categorize_vacancy(query):
query = str(query).lower()
if 'system' in query or 'системный' in query:
return 'Системный аналитик'
if 'data' in query or 'данных' in query:
return 'Аналитик данных'
return 'Другое'
# Применяем функцию
df['vacancy_category'] = df['target_query'].apply(categorize_vacancy)
# Проверим, как распределились новые категории
print(df['vacancy_category'].value_counts())
vacancy_category Аналитик данных 4183 Системный аналитик 1994 Name: count, dtype: int64
display(df.head())
| id | name | published_date | target_city | target_query | city | company | exp_level | job_type | work_schedule | salary_from | salary_to | salary_currency | requirements | vacancy_category | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 131549046 | Аналитик данных | 2026-04-12 | Москва | аналитик данных | Москва | ИКС БИО ТЕХНОЛОДЖИ | От 3 до 6 лет | Полная занятость | Полный день | NaN | NaN | None | ...к аналитике и исследованию данных. Продвину... | Аналитик данных |
| 1 | 131889061 | Аналитик баз данных | 2026-04-12 | Москва | аналитик данных | Москва | Фортис Технологии | От 3 до 6 лет | Полная занятость | Удаленная работа | 80000.0 | 120000.0 | RUR | Навыки работы с СУБД: построение SQL-запросов.... | Аналитик данных |
| 2 | 131978902 | Аналитик данных | 2026-04-12 | Москва | аналитик данных | Москва | Медиабюро Статус презенс | От 1 года до 3 лет | Полная занятость | Полный день | 120000.0 | 150000.0 | RUR | Высшее образование. Аналитический склад ума, в... | Аналитик данных |
| 3 | 131232738 | Аналитик данных | 2026-04-12 | Москва | аналитик данных | Москва | Aviasales.ru | От 3 до 6 лет | Полная занятость | Удаленная работа | NaN | NaN | None | Опыт в дата или продуктовой аналитике от трех ... | Аналитик данных |
| 4 | 131868762 | Аналитик платформы данных | 2026-04-12 | Москва | аналитик данных | Москва | Цифровой аудит | От 3 до 6 лет | Полная занятость | Полный день | NaN | NaN | None | Опыт работы в хранилищах данных (DWH/КХД). Уве... | Аналитик данных |
Обработка названий компаний (Brand Consolidation)¶
При анализе рынка труда важно учитывать структуру крупных холдингов. Часто дочерние ИТ-подразделения (например, SberTech, OzonTech) фигурируют как отдельные юридические лица, что дробит статистику и искажает реальный вес бренда-работодателя.
План действий:
- Выявление топ-15 компаний по объему вакансий.
- Проверка выявленных лидеров на наличие дочерних структур в общем списке.
- Создание функции для унификации названий (приведение «дочек» к материнскому бренду).
Это позволит получить объективный рейтинг крупнейших нанимателей в направлении Data & System Analytics.
print(df['company'].value_counts().head(15))
company СБЕР 202 Ozon 89 ИЦ АЙ-ТЕКО 61 Т-Банк 50 МТС 48 Банк ВТБ (ПАО) 46 RWB (Wildberries & Russ) 42 Альфа-Банк 42 Алабуга, ОЭЗ ППТ 36 VK 36 Совкомбанк 32 АО «ОТП Банк» (JSC «OTP Bank») 32 Центральный банк Российской Федерации (Банк России) 29 Яндекс 28 ГКУ Инфогород 28 Name: count, dtype: int64
В лидеры по количеству открытых позиций вошли крупнейшие игроки банковского сектора, ритейла и ИТ-индустрии: СБЕР, Ozon, Wildberries, Альфа-Банк, МТС, Т-Банк и VK и другие.
Для корректного подсчета я реализую функцию поиска по ключевым словам. Это позволит объединить записи дочерних компаний под единым зонтичным брендом там, где это уместно.
def find_companies(df, search_word):
# Приводим поисковое слово к нижнему регистру
search_word = search_word.lower()
# Ищем совпадения в столбце 'company'
matches = df[df['company'].str.lower().str.contains(search_word, na=False)]
if matches.empty:
print(f"По запросу '{search_word}' ничего не найдено.")
else:
# Группируем и считаем
result = matches['company'].value_counts().reset_index()
result.columns = ['Название в базе', 'Количество вакансий']
print(f"--- Результаты поиска для '{search_word}' ---")
display(result)
Разработанная функция будет применена ко всему датасету. Для оптимизации процесса основной упор сделан на компаниях-лидерах, так как именно в этом сегменте наиболее выражено дробление на дочерние подразделения. Это позволит консолидировать данные без потери информации о масштабах найма крупных игроков.
find_companies(df, 'sber')
print()
find_companies(df, 'сбер')
print()
find_companies(df, 'Russ')
print()
find_companies(df, 'альфа')
print()
find_companies(df, 'мтс')
print()
find_companies(df, 'втб')
print()
find_companies(df, 'яндекс')
print()
find_companies(df, 'газпром')
print()
find_companies(df, 'магнит')
print()
find_companies(df, 'ростелеком')
print()
--- Результаты поиска для 'sber' ---
| Название в базе | Количество вакансий | |
|---|---|---|
| 0 | SberTech | 3 |
--- Результаты поиска для 'сбер' ---
| Название в базе | Количество вакансий | |
|---|---|---|
| 0 | СБЕР | 202 |
| 1 | СберЛизинг | 15 |
| 2 | СБЕРКОРУС | 7 |
| 3 | СберЗдоровье | 6 |
| 4 | СберСпасибо | 3 |
| 5 | Страховая компания Сбербанк страхование | 3 |
| 6 | Сбер Бизнес Софт | 2 |
| 7 | АЙСБЕРГ | 2 |
| 8 | СК Сбербанк страхование жизни | 1 |
| 9 | СберСити | 1 |
| 10 | СберМаркетинг | 1 |
--- Результаты поиска для 'russ' ---
| Название в базе | Количество вакансий | |
|---|---|---|
| 0 | RWB (Wildberries & Russ) | 42 |
| 1 | Russ | 4 |
| 2 | Cornerstone Russia | 2 |
| 3 | Cheil Russia | 1 |
| 4 | INVAIDER RUSSIA | 1 |
--- Результаты поиска для 'альфа' ---
| Название в базе | Количество вакансий | |
|---|---|---|
| 0 | Альфа-Банк | 42 |
| 1 | Альфа-Деньги | 4 |
| 2 | Альфа Капитал | 2 |
| 3 | 1й Нагатинский (СЗ Альфа) | 1 |
| 4 | Альфа-Форекс | 1 |
| 5 | АльфаСпа Косметик | 1 |
| 6 | АльфаСтрахование | 1 |
--- Результаты поиска для 'мтс' ---
| Название в базе | Количество вакансий | |
|---|---|---|
| 0 | МТС | 48 |
| 1 | МТС Банк | 16 |
--- Результаты поиска для 'втб' ---
| Название в базе | Количество вакансий | |
|---|---|---|
| 0 | Банк ВТБ (ПАО) | 46 |
| 1 | ВТБ Факторинг | 2 |
--- Результаты поиска для 'яндекс' ---
| Название в базе | Количество вакансий | |
|---|---|---|
| 0 | Яндекс | 28 |
| 1 | Яндекс Крауд | 3 |
| 2 | Яндекс Команда для бизнеса | 3 |
| 3 | Яндекс.Еда | 2 |
--- Результаты поиска для 'газпром' ---
| Название в базе | Количество вакансий | |
|---|---|---|
| 0 | Газпромбанк | 17 |
| 1 | Газпром нефть | 14 |
| 2 | Газпромнефть-Региональные продажи | 9 |
| 3 | Газпром ЦПС | 8 |
| 4 | Газпром сеть АГЗС | 3 |
| 5 | Газпром информ | 3 |
| 6 | Газпромбанк Лизинг | 2 |
| 7 | Электронная торговая площадка Газпромбанка | 2 |
| 8 | Газпромнефть-Снабжение | 2 |
| 9 | Газпромбанк Автолизинг | 1 |
| 10 | «Газпром энергохолдинг» | 1 |
| 11 | Газпром бурение | 1 |
| 12 | Газпром ТЕХ | 1 |
| 13 | Газпром питание | 1 |
| 14 | Филиал УСЗ ПАО Газпром | 1 |
--- Результаты поиска для 'магнит' ---
| Название в базе | Количество вакансий | |
|---|---|---|
| 0 | МАГНИТ, Розничная сеть | 21 |
| 1 | Магнит OMNI | 3 |
--- Результаты поиска для 'ростелеком' ---
| Название в базе | Количество вакансий | |
|---|---|---|
| 0 | Ростелеком | 18 |
| 1 | Ростелеком Информационные Технологии | 7 |
Результаты поиска дочерних структур¶
Поиск подтвердил наличие значительного количества аффилированных юрлиц, особенно у таких гигантов, как Сбер, Газпром и Альфа-Банк.
Следующий шаг: Выполнение скрипта для унификации названий. Все найденные дочерние структуры будут приведены к единому наименованию материнского бренда для обеспечения точности при визуализации рыночных долей.
# Словарь компаний и их синонимов для поиска
company_mapping = {
'СБЕР': [
'СБЕР', 'СберЛизинг', 'Страховая компания Сбербанк страхование',
'СберЗдоровье', 'СБЕРКОРУС', 'СберСпасибо', 'Сбер Бизнес Софт',
'СберМобайл', 'СК Сбербанк страхование жизни', 'СберПраво',
'Корпоративный университет Сбербанка', 'Сбербанк АСТ', 'SberTech'
],
'RWB (Wildberries & Russ)': [
'RWB (Wildberries & Russ)', 'Russ'
],
'Альфа Банк': [
'Альфа-Банк', 'Альфа-Деньги', 'Альфа Капитал',
'АльфаСтрахование-Жизнь', 'Альфа-Форекс', 'Альфа-Лизинг'
],
'МТС': [
'МТС', 'МТС Банк'
],
'ВТБ': [
'Банк ВТБ (ПАО)', 'ВТБ Лизинг',
'ВТБ Факторинг', 'НПФ ВТБ Пенсионный Фонд'
],
'Яндекс': [
'Яндекс', 'Яндекс Крауд', 'Яндекс.Еда'
],
'ГАЗПРОМ': [
'Газпромбанк', 'Газпром нефть', 'Газпромнефть-Региональные продажи',
'Газпром ЦПС', 'Газпромнефть-Снабжение', 'Газпром сеть АГЗС',
'Электронная торговая площадка Газпромбанка', 'Газпромбанк Автолизинг',
'Газпромбанк Лизинг', 'Газпром экспертиза', 'Газпром информ', 'Газпром питание',
'Филиал УСЗ ПАО Газпром', 'Газпром ТЕХ', '«Газпром энергохолдинг»', 'Газпромтранс', 'Газпром энергосбыт'
],
'МАГНИТ': [
'МАГНИТ, Розничная сеть', 'Магнит OMNI'
],
'Ростелеком': [
'Ростелеком', 'Ростелеком Информационные Технологии'
]
}
# Функция для объединения названий
def clean_company_names(company_name):
for final_name, synonyms in company_mapping.items():
# Проверяем, есть ли текущее название в списке синонимов
if company_name in synonyms:
return final_name
return company_name # Если совпадений нет, оставляем как было
# Применяем очистку к столбцу 'company'
df['company'] = df['company'].apply(clean_company_names)
# Проверяем результат: теперь СБЕР и другие компании должен суммироваться в одну строку
print("Обновленный Топ-15 компаний:")
print(df['company'].value_counts().head(15))
Обновленный Топ-15 компаний: company СБЕР 242 Ozon 89 ГАЗПРОМ 65 МТС 64 ИЦ АЙ-ТЕКО 61 Т-Банк 50 Альфа Банк 49 ВТБ 48 RWB (Wildberries & Russ) 46 Алабуга, ОЭЗ ППТ 36 VK 36 Яндекс 33 АО «ОТП Банк» (JSC «OTP Bank») 32 Совкомбанк 32 Центральный банк Российской Федерации (Банк России) 29 Name: count, dtype: int64
Результаты унификации брендов¶
После объединения дочерних структур под едиными брендами расстановка сил среди крупнейших работодателей существенно изменилась.
Ключевые изменения в Топ-15:
- Лидерство СБЕРа: После консолидации отрыв компании стал еще более значительным (+52 вакансии за счет дочерних подразделений).
- Прорыв ГАЗПРОМа: Компания переместилась с последних мест на 3-е место. Это подтверждает, что значительная часть найма ведется через дочерние ИТ-структуры.
- Банковский сектор и Телеком: Альфа-Банк, МТС и ВТБ также упрочили свои позиции в рейтинге, что позволило получить более объективную картину спроса на специалистов.
Консолидация позволила устранить дробление данных и выявить реальных лидеров рынка, что критически важно для корректного анализа конкуренции среди работодателей.
Контент-анализ Hard Skills: Методология «Золотого стандарта»¶
Особенность данных:
При работе с API HeadHunter поле requirements содержит усеченный фрагмент описания вакансии. Прямое извлечение всех слов из такой выборки может привести к искажению статистики.
Для получения объективной картины применен метод целевого контент-анализа. Вместо обработки «шумного» текста, реализован поиск по списку из 14 ключевых индустриальных стандартов с использованием регулярных выражений.
Преимущества подхода:
- Фильтрация шума: Фокус исключительно на Hard Skills, исключая общие формулировки («ответственность», «командный игрок»).
- Учет вариативности: Использование регулярных выражений (например,
python|питонилиpostgres|sql) позволяет корректно считывать навыки при разном написании. - Релевантность 2026: Выбранный список навыков является «золотым стандартом» для позиций Data и System Analyst, что позволяет провести качественное сравнение направлений.
Список целевых навыков:
- Языки и библиотеки: SQL, Python, Pandas.
- Инструменты BI: Excel, Power BI, Tableau, Superset.
- Data Engineering: Spark, Airflow, ETL, ClickHouse.
- Дополнительно: A/B тесты, Английский язык, Git.
Прежде чем переходить к массовому извлечению, реализуем вспомогательный скрипт для экспресс-проверки: убедимся, что выбранные ключевые слова корректно распознаются в тексте вакансий.
def find_requirements(df, search_word):
# Приводим поисковое слово к нижнему регистру
search_word = search_word.lower()
# Ищем совпадения в столбце 'requirements'
matches = df[df['requirements'].str.lower().str.contains(search_word, na=False)]
if matches.empty:
print(f"По запросу '{search_word}' ничего не найдено.")
else:
# Группируем и считаем
result = matches['requirements'].value_counts().reset_index()
result.columns = ['Название в базе', 'Количество вакансий']
print(f"--- Результаты поиска для '{search_word}' ---")
display(result)
find_requirements(df, 'sql')
find_requirements(df, 'Airflow')
find_requirements(df, 'английский')
find_requirements(df, 'python')
find_requirements(df, 'spark')
find_requirements(df, 'tableau')
find_requirements(df, 'power bi')
find_requirements(df, 'English')
find_requirements(df, 'pandas')
find_requirements(df, 'etl')
find_requirements(df, 'a/b')
find_requirements(df, 'Git')
find_requirements(df, 'ClickHouse')
find_requirements(df, 'superset')
--- Результаты поиска для 'sql' ---
| Название в базе | Количество вакансий | |
|---|---|---|
| 0 | Уверенное владение Python (pandas, numpy) для ... | 3 |
| 1 | SQL на высоком уровне: уверенное владение окон... | 3 |
| 2 | Опыт работы с данными от 2 лет (дата-инженер, ... | 3 |
| 3 | Опыт работы с микросервисной архитектурой. Опы... | 3 |
| 4 | ...моделирования данных: Dimensional Modeling,... | 2 |
| ... | ... | ... |
| 658 | Свободное владение SQL: уверенное написание сл... | 1 |
| 659 | Высшее образование. Опыт работы на позиции Ана... | 1 |
| 660 | Углублённые знания Power BI (Power Query, M, D... | 1 |
| 661 | Опыт взаимодействия с промышленными СУБД: Orac... | 1 |
| 662 | Работа с базами данных (SQL) — умение оптимизи... | 1 |
663 rows × 2 columns
--- Результаты поиска для 'airflow' ---
| Название в базе | Количество вакансий | |
|---|---|---|
| 0 | Опыт работы аналитиком данных более 3 лет. Опы... | 2 |
| 1 | Опыт работы с AirFlow, Git. Знание pyhon для а... | 1 |
| 2 | ...ключи, индексы и планы запросов. Опыт разра... | 1 |
| 3 | Опыт проектирования масштабируемых решений для... | 1 |
| 4 | Опыт в системном анализе ETL, проектировании п... | 1 |
| 5 | MLOps: работа с TensorFlow в продакшене, DVC, ... | 1 |
| 6 | Имеете опыт работы с инструментами аналитиков ... | 1 |
| 7 | 3+ лет опыта в роли Data Engineer / BI Enginee... | 1 |
| 8 | Высшее образование. Продвинутые навыки в разра... | 1 |
| 9 | Высшее техническое или финансово-математическо... | 1 |
| 10 | Опыт работы с orchestration-инструментами (Air... | 1 |
| 11 | Уверенный опыт работы Data Engineer от 2–3 лет... | 1 |
| 12 | ...данных – AirFlow, Nifi, SSIS или другие. Же... | 1 |
| 13 | Опыт работы с BI-системами и визуализацией дан... | 1 |
| 14 | Продвинутые навыки работы с SQL: написание сло... | 1 |
| 15 | Опыт работы с Airflow или аналогичными оркестр... | 1 |
| 16 | ...системами (SuperSet, Reedash и аналогичными... | 1 |
| 17 | Spark, Hadoop, Airflow – плюс. Способность фор... | 1 |
| 18 | ETL/ELT-инструменты, dbt или аналог. Оркестрац... | 1 |
| 19 | Python, pyspark, sql (clickhouse, vertica, pos... | 1 |
| 20 | Умеете осуществлять оркестрацию с помощью airf... | 1 |
| 21 | MS SQL. Apache Airflow. Apache Kafka. Gitlab. ... | 1 |
| 22 | Инженерия данных: понимание архитектуры (Airfl... | 1 |
| 23 | Знание Git (ветвление, merge requests, code re... | 1 |
| 24 | От 2-х лет опыта работы Data Engineer. Хорошее... | 1 |
--- Результаты поиска для 'английский' ---
| Название в базе | Количество вакансий | |
|---|---|---|
| 0 | Опыт работы продуктовым менеджером в B2B (FinT... | 2 |
| 1 | Опыт работы системным/бизнес/full-stack аналит... | 2 |
| 2 | Навыки работы с СУБД: построение SQL-запросов.... | 1 |
| 3 | Уверенное владение SQL, опыт написания bash-ск... | 1 |
| 4 | Умение понимать код на С. Владение языками нот... | 1 |
| 5 | Базовых навыков работы с данными (SQL). Англий... | 1 |
| 6 | Свободный английский язык (устный и письменный... | 1 |
| 7 | Техническое образование. Опыт работы разработч... | 1 |
| 8 | Имеет законченное высшее образование. Имеет ур... | 1 |
| 9 | Хорошо разбираешься в ставках. Любовь и знание... | 1 |
| 10 | ...аналитики от 3 лет. Английский язык (чтение... | 1 |
| 11 | Английский язык - Upper-intermediate +. Опыт в... | 1 |
| 12 | Опыт управления распределенными командами от 7... | 1 |
| 13 | Сильная экспертиза в SEO и performance-маркети... | 1 |
| 14 | Аналитический склад ума: умение работать с бол... | 1 |
| 15 | Сильные аналитические навыки и опыт оптимизаци... | 1 |
| 16 | Высшее образование, в приоритете международный... | 1 |
| 17 | Английский язык Upper-Intermediate B2+ | финал... | 1 |
| 18 | Английский язык на уровне чтения технической д... | 1 |
| 19 | Опыт работы бизнес ассистентом / project-менед... | 1 |
| 20 | Английский язык — письменный и устный. Опыт ра... | 1 |
| 21 | Опыт в поддержке от полугода. Английский язык ... | 1 |
| 22 | Опыт работы с аналитикой и дашбордами (Google ... | 1 |
| 23 | Обязательно – только очная форма обучения. Обя... | 1 |
| 24 | Знает английский язык на уровне С1. Имеет опыт... | 1 |
| 25 | Опыт работы с Airflow или аналогичными оркестр... | 1 |
| 26 | Опыт работы с Python и SQL для анализа данных ... | 1 |
| 27 | Опыт работы системным аналитиком от полутора л... | 1 |
| 28 | Высшее образование (техническое), желательно М... | 1 |
| 29 | Владеет английский языком не ниже Upper-interm... | 1 |
| 30 | Понимание в области разработки концептуальных ... | 1 |
| 31 | Уверенный уровень Microsoft Office, особенно P... | 1 |
| 32 | Понимание принципов работы реляционных (Postgr... | 1 |
| 33 | ...компьютеры, операционные системы) - обязате... | 1 |
| 34 | Понимание бизнес-процессов в сегментах жилой и... | 1 |
| 35 | Умение доводить проекты от идеи до аналитики р... | 1 |
| 36 | Английский не ниже B1 — для глобальных инсайто... | 1 |
| 37 | Опыт 2–4 года в аналитике (Marketplace / Mobil... | 1 |
| 38 | Продвинутый Excel и PowerPoint, умение обрабат... | 1 |
| 39 | Свободный английский язык. Являются плюсом: - ... | 1 |
| 40 | Выпускник с математическим/техническим образов... | 1 |
| 41 | Выпускник с математическим/техническим образов... | 1 |
| 42 | 6+ лет коммерческой разработки на Python. Увер... | 1 |
| 43 | Опыт работы с аналитикой и дашбордами (Google ... | 1 |
| 44 | Английский язык: B1+ (переписка, контент, созв... | 1 |
--- Результаты поиска для 'python' ---
| Название в базе | Количество вакансий | |
|---|---|---|
| 0 | Уверенное владение Python (pandas, numpy) для ... | 3 |
| 1 | ...SQL запросов для самостоятельного сбора и а... | 2 |
| 2 | Навыки работы с базами данных и знание основны... | 2 |
| 3 | SQL: уверенные базовые знания, готовность писа... | 2 |
| 4 | Уверенно работаете с Python и SQL, знаете осно... | 2 |
| ... | ... | ... |
| 306 | Опыт работы бизнес-аналитиком / продуктовым ан... | 1 |
| 307 | Опыт работы с Python (Pandas, NumPy, Jupyter) ... | 1 |
| 308 | Высшее математическое, техническое образование... | 1 |
| 309 | Опыт алгоритмической работы в Python. Навыки р... | 1 |
| 310 | Работа в офисе в Казани с 9 до 18 ч. Уверенное... | 1 |
311 rows × 2 columns
--- Результаты поиска для 'spark' ---
| Название в базе | Количество вакансий | |
|---|---|---|
| 0 | Опыт работы от 3 лет в роли дата аналитика. Ув... | 1 |
| 1 | Свободное владение SQL, Python (Pandas, NumPy)... | 1 |
| 2 | Опыт разработки ETL-процессов. Опыт работы с B... | 1 |
| 3 | Хорошее знание Pytorch. Опыт написания SQL зап... | 1 |
| 4 | Уверенное знание Python. Опыт работы с Big Dat... | 1 |
| 5 | ...backtesting), PnL-анализ, построение индика... | 1 |
| 6 | Высшее техническое или финансово-математическо... | 1 |
| 7 | Опыт работы с Kubernetes от 2 лет. Опыт с Big ... | 1 |
| 8 | Продвинутый уровень SQL и опыт оптимизации зап... | 1 |
| 9 | Знание PySpark, SQL. Опыт модельной аналитики ... | 1 |
| 10 | Опыт работы с Python, включая стандартный data... | 1 |
| 11 | Опыт работы с Big Data инструментами (Hadoop, ... | 1 |
| 12 | Имеете опыт работы с инструментами аналитиков ... | 1 |
| 13 | Опыт работы с современным стеком: ClickHouse, ... | 1 |
| 14 | Опыт с экосистемой Сбера: Platform V (SDP Hado... | 1 |
| 15 | Опыт работы с современным стеком: ClickHouse, ... | 1 |
| 16 | Понимание основ облачных технологий и технолог... | 1 |
| 17 | хорошо владеете Python, pySpark и SQL. – поним... | 1 |
| 18 | Разработка: Уверенное знание Python (asyncio, ... | 1 |
| 19 | Опыт в системном анализе ETL, проектировании п... | 1 |
| 20 | Опыт работы с экосистемой Apache Hadoop (Hive,... | 1 |
| 21 | Понимание архитектуры DWH и принципов построен... | 1 |
| 22 | Опыт работы в системной аналитике, опыт разраб... | 1 |
| 23 | Глубокое знание SQL. Знание HDFS и Apache Spar... | 1 |
| 24 | Имеете уверенный опыт программирования на Pyth... | 1 |
| 25 | SQL, Hadoop, Hive, Spark. Опыт от 2-х лет (Обя... | 1 |
| 26 | ...NumPy, Dbeaver, Spark, BI. Продвинутые знан... | 1 |
| 27 | ...и управления качеством данных. Знание техно... | 1 |
| 28 | Будет плюсом опыт работы со Spark и умение соз... | 1 |
| 29 | ...инструментами: python на уровне аналитика д... | 1 |
| 30 | Опыт работы с базами данных в качестве разрабо... | 1 |
| 31 | Python, pyspark, sql (clickhouse, vertica, pos... | 1 |
| 32 | Имеете опыт работы с: Python; SQL, PySpark. Ув... | 1 |
| 33 | Опыт работы в финансовом секторе от 3-х лет бу... | 1 |
| 34 | Опыт работы с grpc запросами. Опыт тестировани... | 1 |
| 35 | Spark, Hadoop, Airflow – плюс. Способность фор... | 1 |
| 36 | Имеете опыт работы аналитиком данных от 2х лет... | 1 |
| 37 | Опыт работы c Py/Spark. Знание понятий и конце... | 1 |
| 38 | моделирования, концепции статистической провер... | 1 |
| 39 | ...pyspark, Altair; извлечение\загрузка данных... | 1 |
| 40 | Технический стек: Python (библиотеки дата-анал... | 1 |
| 41 | ...запросов, построение и поддержка структур д... | 1 |
| 42 | Базовое знание SQL, Python на уровне, достаточ... | 1 |
| 43 | Имеете глубокие знания SQL, Python, PySpark. И... | 1 |
| 44 | Знание Hadoop, Data Warehouse, Data Lake. Опыт... | 1 |
| 45 | Data & Infra: - Уверенное владение SQL (сложны... | 1 |
| 46 | Data & Infra: - Уверенное владение SQL (сложны... | 1 |
| 47 | Kubernetes: опыт администрирования от 2 лет. B... | 1 |
--- Результаты поиска для 'tableau' ---
| Название в базе | Количество вакансий | |
|---|---|---|
| 0 | ...Power BI, Looker, Tableau). Умение формулир... | 3 |
| 1 | Хорошее знание SQL (join, оконные функции, вло... | 2 |
| 2 | Глубокое знание SQL и умение эффективно работа... | 2 |
| 3 | Продвинутый уровень SQL. Регулярное использова... | 2 |
| 4 | Более 3 лет работал в качестве аналитика. Имее... | 1 |
| 5 | Написание SQL-запросов для выгрузки и проверки... | 1 |
| 6 | Уверенные навыки работы с Excel (обработка дан... | 1 |
| 7 | Уверенное владение Python для задач продакшн-а... | 1 |
| 8 | Опыт построения сложной BI отчетности (в любой... | 1 |
| 9 | Опыт построения продуктовой аналитики. - Умени... | 1 |
| 10 | Уверенное владение SQL, Python и современными ... | 1 |
| 11 | Опыт работы с системами визуализации (Power BI... | 1 |
| 12 | Высокий уровень SQL (в частности, оптимизация ... | 1 |
| 13 | Опыт построения Dashboards в BI системах : Qli... | 1 |
| 14 | Инструменты Business Intelligence: уверенный о... | 1 |
| 15 | В зависимости от продукта и масштабов исследов... | 1 |
| 16 | Опыт работы с системами аналитики (Power BI, T... | 1 |
| 17 | ...визуализации данных (например, Tableau, Pow... | 1 |
| 18 | Опыт построения отчетов и аналитики: Looker St... | 1 |
| 19 | Специалиста, для которого преимуществом будет ... | 1 |
| 20 | Техническая грамотность: базовое понимание код... | 1 |
| 21 | Высшее образование: маркетинг, социология, ста... | 1 |
| 22 | Опыт работы с BI‑инструментами (Power BI/Table... | 1 |
| 23 | Уверенное знание SQL (сложные запросы, оконные... | 1 |
| 24 | Опыт запуска аналитики с нуля. Опыт в маркетин... | 1 |
| 25 | Навыки работы с инструментами анализа данных (... | 1 |
| 26 | Понимание рекламных кабинетов/аналитики. BI-ин... | 1 |
| 27 | Продвинутый уровень SQL: Базовый уровень Pytho... | 1 |
| 28 | Продвинутое владение Excel/Google Sheets (форм... | 1 |
| 29 | Знание Python на уровне обработки и анализа да... | 1 |
| 30 | ...24, AmoCRM) через API. Работа с другими BI-... | 1 |
| 31 | Power BI / Tableau — средний уровень. 1С — баз... | 1 |
| 32 | Опыт работы аналитиком данных от 3 лет. Опыт р... | 1 |
| 33 | SQL: Vertica, ClickHouse. Будет плюсом: Опыт р... | 1 |
| 34 | Навык построения дашбордов и визуализации данн... | 1 |
| 35 | Опыт построения отчетности в Apache Superset н... | 1 |
| 36 | Опыт работы с системами бизнес-аналитики (Powe... | 1 |
| 37 | Уверенный SQL. Уверенный Python для аналитики ... | 1 |
| 38 | Продвинутое владение Excel/Google Sheets (форм... | 1 |
| 39 | Навыки работы с Excel (сводные таблицы, формул... | 1 |
| 40 | Знание инструментов аналитики (Excel, Power BI... | 1 |
| 41 | Умение работать с большими массивами данных, в... | 1 |
| 42 | Желательно, чтобы вы знали инструменты анализа... | 1 |
| 43 | Используете Python для выгрузки и обработки бо... | 1 |
| 44 | Баумана, НИУ ВШЭ, МГУ. Опыт визуализации данны... | 1 |
| 45 | Понимание основных алгоритмов и структур данны... | 1 |
| 46 | Опыт работы BI-аналитиком от 3 лет. Глубокое з... | 1 |
| 47 | Понимание ключевых метрик Ozon: Конверсия. CTR... | 1 |
| 48 | Навыки работы с BI‑инструментами (Power BI, Ta... | 1 |
| 49 | Power BI или Tableau для визуализации данных -... | 1 |
| 50 | Опыт работы с большими данными и сложными стру... | 1 |
| 51 | Опыт работы с Power BI, Tableau, Data Studio д... | 1 |
| 52 | Опыт работы с инструментами визуализации и ана... | 1 |
--- Результаты поиска для 'power bi' ---
| Название в базе | Количество вакансий | |
|---|---|---|
| 0 | ...Power BI, Looker, Tableau). Умение формулир... | 3 |
| 1 | Опыт разработки отчетов и дашбордов в Power BI... | 2 |
| 2 | Владение инструментами аналитики (например, Po... | 2 |
| 3 | ...большими массивами данных. Владение Excel (... | 2 |
| 4 | Продвинутый уровень SQL. Регулярное использова... | 2 |
| ... | ... | ... |
| 110 | Уверенное построение факторных и финансовых мо... | 1 |
| 111 | Требования: Практический опыт с Power BI / DAX... | 1 |
| 112 | Навыки работы с Excel (сводные таблицы, формул... | 1 |
| 113 | Опыт работы с большими массивами данных. Навык... | 1 |
| 114 | Навыки работы с аналитикой: Я.Метрика, GA4, Po... | 1 |
115 rows × 2 columns
--- Результаты поиска для 'english' ---
| Название в базе | Количество вакансий | |
|---|---|---|
| 0 | English language proficiency level C1+. Quickl... | 2 |
| 1 | Bachelor’s degree required. Bachelor’s degree ... | 1 |
| 2 | Fluent English: Ты свободно питчишь, шутишь и ... | 1 |
| 3 | Опыт от 1 года: в операциях, аналитике, консал... | 1 |
| 4 | AI-Native Development Skills. Communication Sk... | 1 |
--- Результаты поиска для 'pandas' ---
| Название в базе | Количество вакансий | |
|---|---|---|
| 0 | Уверенное владение Python (pandas, numpy) для ... | 3 |
| 1 | ...структур данных для аналитики). Опыт примен... | 2 |
| 2 | SQL: уверенные базовые знания, готовность писа... | 2 |
| 3 | Владение методами анализа данных с использован... | 2 |
| 4 | Образование в профильной или смежной области. ... | 2 |
| ... | ... | ... |
| 58 | Высшее образование. Владение Python для анализ... | 1 |
| 59 | Опыт работы в сфере аналитики данных от 3 лет.... | 1 |
| 60 | ...запросов, построение и поддержка структур д... | 1 |
| 61 | ...в аналитике от 1 года. Опыт работы на Pytho... | 1 |
| 62 | Обязательно: Python (pandas, numpy, scikit-lea... | 1 |
63 rows × 2 columns
--- Результаты поиска для 'etl' ---
| Название в базе | Количество вакансий | |
|---|---|---|
| 0 | Не менее 2 лет работы в качестве Data Engineer... | 2 |
| 1 | Опыт в доработках хранилищ данных: исследовани... | 2 |
| 2 | Опыт работы от 2х лет в роли Data Engineer, Da... | 2 |
| 3 | Опыт участия в разработке систем обработки дан... | 1 |
| 4 | ...Data modeling, ETL/ELT, lakehouse архитекту... | 1 |
| ... | ... | ... |
| 70 | Опыт работы с Airflow или аналогичными оркестр... | 1 |
| 71 | Продвинутые навыки автоматизации (ETL), постро... | 1 |
| 72 | Моделирование данных: OLAP-куб, DWH. Python - ... | 1 |
| 73 | Занимаешься data analytics / data engineering ... | 1 |
| 74 | Знание ClickHouse. -Знание Python. -Опыт получ... | 1 |
75 rows × 2 columns
--- Результаты поиска для 'a/b' ---
| Название в базе | Количество вакансий | |
|---|---|---|
| 0 | Мы ищем продуктового/data аналитика с большим ... | 3 |
| 1 | Навыки количественного и качественного исследо... | 2 |
| 2 | Практический опыт работы с аналитикой: SQL-зап... | 2 |
| 3 | Глубокие знание математической статистики и пр... | 2 |
| 4 | Уверенный Excel (сводные таблицы, статистика, ... | 2 |
| 5 | Свободное владение SQL, Python (Pandas, NumPy)... | 1 |
| 6 | Опыт: Успешные кейсы по оптимизации продукта н... | 1 |
| 7 | Готовность развиваться в этом направлении. Dat... | 1 |
| 8 | Опыт работы с мобильной аналитикой (Amplitude,... | 1 |
| 9 | Образование: Высшее техническое или в сфере IT... | 1 |
| 10 | ...аналитике. Понимание продуктовой аналитики:... | 1 |
| 11 | Умение работать с продуктовой аналитикой и при... | 1 |
| 12 | Будет плюсом. Опыт работы в SaaS / стартапах. ... | 1 |
| 13 | Data‑driven подход: умение задавать требования... | 1 |
| 14 | Понимание CI/CD, сборок, автоматизации, пайпла... | 1 |
| 15 | Навыки проведения A/B тестирования. Знание сис... | 1 |
| 16 | Опыт проведения A/B-тестирования (креативы, ау... | 1 |
| 17 | Сильный data-driven подход и опыт A/B-тестиров... | 1 |
| 18 | Data-driven мышление (эксперименты, A/B-тесты,... | 1 |
| 19 | Понимание и использование метрик (CTR, CR, охв... | 1 |
| 20 | Имеете опыт проведения A/B тестов. Понимаете M... | 1 |
| 21 | Понимание маркетинговых воронок и навыки A/B-т... | 1 |
| 22 | +Базовые знания в области AI/ML, LLM и аналити... | 1 |
| 23 | Опыт работы в аналитике (Data/Business Analyst... | 1 |
| 24 | A/B тесты, генерация и проверка гипотез - быть... | 1 |
| 25 | SQL: уверенное владение. Python: статпакеты / ... | 1 |
| 26 | Опыт в продуктовой аналитике от трёх лет. Прик... | 1 |
| 27 | Уверенный SQL (PostgreSQL / ClickHouse / Terad... | 1 |
| 28 | Опыт работы в роли аналитика клиентских данных... | 1 |
| 29 | Наши ожидания: — Уверенное владение Excel. — О... | 1 |
| 30 | Отличные знания математической статистики: Нав... | 1 |
| 31 | Понимание принципов A/B тестирования. Умение р... | 1 |
| 32 | Опыт работы в продуктовой аналитике в одной из... | 1 |
| 33 | Анализировать качество модели и её влияние на ... | 1 |
| 34 | Опыт исследовательской деятельности в роли Dat... | 1 |
--- Результаты поиска для 'git' ---
| Название в базе | Количество вакансий | |
|---|---|---|
| 0 | Опыт в digital marketing от 2 лет. Понимание, ... | 2 |
| 1 | Опыт в телемаркетинге или продажах от 6 месяце... | 2 |
| 2 | Опыт написания SQL запросов для чтения и модиф... | 2 |
| 3 | Умение разобраться в любой lineage-цепочке дан... | 2 |
| 4 | Знание основ digital-маркетинга и умение работ... | 2 |
| ... | ... | ... |
| 103 | Сильные аналитические навыки и работа с digita... | 1 |
| 104 | Опыт работы с технологиями по направлению Java... | 1 |
| 105 | Релевантный опыт работы на стороне рекламного ... | 1 |
| 106 | Разбираешься в digital и медийных инструментах... | 1 |
| 107 | Высшее профильное образование (маркетинг, рекл... | 1 |
108 rows × 2 columns
--- Результаты поиска для 'clickhouse' ---
| Название в базе | Количество вакансий | |
|---|---|---|
| 0 | SQL на высоком уровне: уверенное владение окон... | 3 |
| 1 | Уверенное владение Python (pandas, numpy) для ... | 3 |
| 2 | Опыт в продуктовой аналитике от 1 года. Сильны... | 2 |
| 3 | ...источников данных. Глубокие знания SQL, опы... | 2 |
| 4 | Опыт ClickHouse и/или PostgreSQL: проектирован... | 1 |
| 5 | Опыт работы с современным стеком: ClickHouse, ... | 1 |
| 6 | Опыт построения Data Lakehouse-архитектуры с н... | 1 |
| 7 | Опыт работы Data Engineer / DWH Engineer / ETL... | 1 |
| 8 | Уверенное знание Python. Опыт работы с Big Dat... | 1 |
| 9 | Коммерческий опыт работы с ClickHouse от 1 год... | 1 |
| 10 | Высшее образование. Опыт в продуктовой/data-ан... | 1 |
| 11 | Опыт работы с Clickhouse или оптимизации запро... | 1 |
| 12 | Опыт работы с Clickhouse. Опыт в интернет-марк... | 1 |
| 13 | Опыт проектирования хранилищ данных. Знание ос... | 1 |
| 14 | Опыт работы с современным стеком: ClickHouse, ... | 1 |
| 15 | Ориентируетесь в предметных областях: управлен... | 1 |
| 16 | ClickHouse. Greenplum. Trino. Python. Data Lak... | 1 |
| 17 | Хорошая математическая база (ТеорВер, МатСтат)... | 1 |
| 18 | Технологии и стек: - Микросервисы, REST, Kafka... | 1 |
| 19 | Опыт работы в роли системного аналитика от 3 л... | 1 |
| 20 | Опыт разработки высоконагруженных web-проектов... | 1 |
| 21 | ...и/или ClickHouse (желательно). Будет плюсом... | 1 |
| 22 | Опыт работы BI-аналитиком, data-аналитиком или... | 1 |
| 23 | Опыт работы в качестве системного аналитика не... | 1 |
| 24 | Глубокое знание SQL, опыт работы с СУБД Clickh... | 1 |
| 25 | Глубокие знания ClickHouse или других OLAP-сис... | 1 |
| 26 | ...Sql базами данных (у нас MySQL и своё key-v... | 1 |
| 27 | От 2-х лет опыта работы Data Engineer. Хорошее... | 1 |
| 28 | Знание ClickHouse. -Знание Python. -Опыт получ... | 1 |
| 29 | Писать бизнес-логику на Golang или Python. Вла... | 1 |
| 30 | Опыт коммерческой работы дата-аналитиком, инже... | 1 |
| 31 | Опыт работы с ClickHouse. Понимание основ DWH ... | 1 |
| 32 | Опыт работы с большими объёмами данных и сложн... | 1 |
| 33 | Уверенные технические знания: профи в SQL и оп... | 1 |
| 34 | ...с большими массивами данных (обязательное з... | 1 |
| 35 | Знание SQL на уровне не ниже мидл (опыт работы... | 1 |
| 36 | Знание SQL (Postrgre, ClickHouse), Python. Опы... | 1 |
| 37 | Имеете опыт работы аналитиком данных от 3 лет.... | 1 |
| 38 | Знание Git (ветвление, merge requests, code re... | 1 |
| 39 | Опыт работы в качестве системного аналитика от... | 1 |
| 40 | Глубокое понимание принципов структуры баз дан... | 1 |
| 41 | Уверенно работаешь с большими объемами данных ... | 1 |
| 42 | Опыт работы с базами данных: PostgreSQL, Click... | 1 |
| 43 | Уверенное владение SQL (желательно ClickHouse)... | 1 |
| 44 | Опыт работы в продуктовой аналитике в одной из... | 1 |
| 45 | SQL: Vertica, ClickHouse. Будет плюсом: Опыт р... | 1 |
| 46 | Python, pyspark, sql (clickhouse, vertica, pos... | 1 |
| 47 | Уверенно пишет на SQL (ClickHouse — наш основн... | 1 |
| 48 | ETL/ELT-инструменты, dbt или аналог. Оркестрац... | 1 |
| 49 | Отличное знание SQL. Опыт работы с Clickhouse.... | 1 |
| 50 | Высшее образование (математическое, экономичес... | 1 |
| 51 | ...схемы стриминга данных Я.Метрики и/или Data... | 1 |
| 52 | Составление ER-диаграмм и схем миграции данных... | 1 |
| 53 | Уверенный SQL (PostgreSQL / ClickHouse / Terad... | 1 |
| 54 | Работа с большими данными: понимаем особенност... | 1 |
| 55 | Баумана, НИУ ВШЭ, МГУ. Опыт визуализации данны... | 1 |
| 56 | Kafka/RabbitMQ/SQS. Опыт с хранилищами и анали... | 1 |
--- Результаты поиска для 'superset' ---
| Название в базе | Количество вакансий | |
|---|---|---|
| 0 | Хорошее знание SQL (join, оконные функции, вло... | 2 |
| 1 | Знание Python на продвинутом уровне (pyodbs, p... | 1 |
| 2 | Высокий уровень SQL (в частности, оптимизация ... | 1 |
| 3 | ...аналитиком от 2-х лет. ️ Отличное знание SQ... | 1 |
| 4 | Опыт визуализации данных с BI инструментами - ... | 1 |
| 5 | Хорошая математическая база (ТеорВер, МатСтат)... | 1 |
| 6 | Уверенное владение Python для задач продакшн-а... | 1 |
| 7 | Опыт построения сложной BI отчетности (в любой... | 1 |
| 8 | Опыт построения продуктовой аналитики. - Умени... | 1 |
| 9 | Опыт работы с системами визуализации (Power BI... | 1 |
| 10 | Опыт построения Dashboards в BI системах : Qli... | 1 |
| 11 | Инструменты Business Intelligence: уверенный о... | 1 |
| 12 | Более 3 лет работал в качестве аналитика. Имее... | 1 |
| 13 | ...Data Strategy & Governance) и процессов по ... | 1 |
| 14 | Навыки визуализации информации в BI-системах (... | 1 |
| 15 | Уверенное знание SQL (сложные запросы, оконные... | 1 |
| 16 | Понимание рекламных кабинетов/аналитики. BI-ин... | 1 |
| 17 | Имеет опыт разработки дашбордов и отчетов в од... | 1 |
| 18 | ...визуализации данных (например, Tableau, Pow... | 1 |
| 19 | Свободное владение SQL (сложные запросы, оконн... | 1 |
| 20 | Опыт работы в клиентской аналитике от 2 лет. S... | 1 |
| 21 | 3 года опыта работы в BI-аналитике: умение стр... | 1 |
| 22 | Высокий уровень владения SQL, Python. Опыт раб... | 1 |
| 23 | Имеете опыт работы с Superset. Владеете на выс... | 1 |
| 24 | Высшее образование (математика, ИТ, экономика ... | 1 |
| 25 | Опыт работы аналитиком данных от 3 лет. Опыт р... | 1 |
| 26 | Доступный стек: PL SQL, Greenplum, Python; Fin... | 1 |
| 27 | SQL: Vertica, ClickHouse. Будет плюсом: Опыт р... | 1 |
| 28 | Опыт построения отчетности в Apache Superset н... | 1 |
| 29 | Знание Python на продвинутом уровне (pyodbs, p... | 1 |
| 30 | Навыки SQL, Python, SuperSet. Знание математич... | 1 |
| 31 | ...системами (SuperSet, Reedash и аналогичными... | 1 |
| 32 | Высшее образование (математическое, экономичес... | 1 |
| 33 | Apache Superset (или BI аналоги). Понимание А/... | 1 |
| 34 | Поддержка и развитие базы знаний. Есть опыт ра... | 1 |
| 35 | Высшее образование в области аналитики, матема... | 1 |
| 36 | Понимание и использование ML-алгоритмов для ан... | 1 |
| 37 | Понимание основных алгоритмов и структур данны... | 1 |
| 38 | Навыки по формированию отчётности "под ключ" в... | 1 |
Проверка подтвердила наличие всех целевых навыков в выборке. Данные репрезентативны и готовы к агрегации.
Следующий шаг: Создание функции extract_skills для автоматизированного подсчета частоты упоминаний каждого навыка. Результаты этой функции станут основой для сравнительного анализа требований.
# Словарь навыков и их синонимов для поиска. Использую регулярные выражения, т.к. ищу определенные слова в кучке текста
skills_map = {
'SQL': r'sql|postgres|oracle|msql',
'Python': r'python|питон',
'Spark': r'spark',
'Pandas': r'pandas|пандиас',
'Excel': r'excel|эксель|vlookup|сводные таблицы',
'Power BI': r'power\s?bi|pbi|повер би',
'Tableau': r'tableau|табло',
'Superset': r'superset|суперсет',
'Airflow': r'airflow|эйрфлоу',
'ETL': r'etl|extraction',
'ClickHouse': r'clickhouse|кликхаус',
'A/B тесты': r'a/b|ab-test|эксперимент|тестирование',
'Английский язык': r'english|английский|eng|upper|intermediate',
'Git': r'git|gitlab|github'
}
# Функция для создания колонок навыков
def extract_skills(df, skills_dict):
# Копируем датафрейм, чтобы не испортить оригинал
processed_df = df.copy()
# Заполняем пустые требования пустой строкой, чтобы поиск не сломался
processed_df['requirements'] = processed_df['requirements'].fillna('').str.lower()
for skill, pattern in skills_dict.items():
# Создаем новую колонку: 1 если паттерн найден, иначе 0
column_name = f'skill_{skill}'
processed_df[column_name] = processed_df['requirements'].str.contains(pattern, na=False).astype(int)
return processed_df
# Применяем функцию
df = extract_skills(df, skills_map)
# Проверим результат: создадим генератор списка по столбцам начинающимся с skill_ и суммы по новым колонкам:
skill_columns = [col for col in df.columns if col.startswith('skill_')]
print("Количество упоминаний каждого навыка:")
print(df[skill_columns].sum().sort_values(ascending=False))
Количество упоминаний каждого навыка: skill_SQL 727 skill_Excel 606 skill_Python 333 skill_Power BI 132 skill_Git 114 skill_Английский язык 108 skill_ETL 79 skill_Pandas 69 skill_ClickHouse 63 skill_A/B тесты 60 skill_Tableau 58 skill_Spark 48 skill_Superset 40 skill_Airflow 26 dtype: int64
display(df.head(2))
| id | name | published_date | target_city | target_query | city | company | exp_level | job_type | work_schedule | salary_from | salary_to | salary_currency | requirements | vacancy_category | skill_SQL | skill_Python | skill_Spark | skill_Pandas | skill_Excel | skill_Power BI | skill_Tableau | skill_Superset | skill_Airflow | skill_ETL | skill_ClickHouse | skill_A/B тесты | skill_Английский язык | skill_Git | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 131549046 | Аналитик данных | 2026-04-12 | Москва | аналитик данных | Москва | ИКС БИО ТЕХНОЛОДЖИ | От 3 до 6 лет | Полная занятость | Полный день | NaN | NaN | None | ...к аналитике и исследованию данных. продвину... | Аналитик данных | 1 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | 131889061 | Аналитик баз данных | 2026-04-12 | Москва | аналитик данных | Москва | Фортис Технологии | От 3 до 6 лет | Полная занятость | Удаленная работа | 80000.0 | 120000.0 | RUR | навыки работы с субд: построение sql-запросов.... | Аналитик данных | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
# Сохранение очищенных данных
df.to_csv('hh_vacancies_data.csv', index=False, encoding='utf-8-sig')
# Сохранение неочищенных данных
df_full.to_csv('hh_vacancies_raw.csv', index=False, encoding='utf-8-sig')
# Посмотрим вес двух файлов
import os
print(f"Размер файла: {os.path.getsize('hh_vacancies_data.csv') / 1024:.2f} КБ")
print(f"Размер файла: {os.path.getsize('hh_vacancies_raw.csv') / 1024:.2f} КБ")
Размер файла: 3520.58 КБ Размер файла: 17665.22 КБ
Итоги этапа предобработки¶
- Трансформация структур: Выполнена фильтрация избыточных признаков и распаковка вложенных JSON-структур в плоские столбцы.
- Текстовый процессинг:
- Проведена очистка описаний вакансий от HTML-тегов и нерелевантных символов.
- Реализован контент-анализ для извлечения ключевых Hard Skills.
- Нормализация данных:
- Стандартизированы названия компаний и сгруппированы поисковые запросы.
- Оптимизировано представление дат для корректного временного анализа.
- Работа с финансовыми показателями: Проведен аудит полноты данных по столбцам заработной платы и подготовлена база для расчета средних значений.
В результате очистки, объем обрабатываемой информации был существенно оптимизирован.
- Размер исходных данных: ~17.3 МБ
- Размер очищенного датасета: ~3.4 МБ
Результат: Вес файла уменьшился в 5 раз при сохранении всей ключевой информации для анализа. Это не только ускоряет работу скриптов визуализации, но и подготавливает данные к эффективному хранению.
Данные очищены и готовы к этапу исследовательского анализа.
IV. Исследовательский анализ данных (EDA)¶
На данном этапе мы переходим к поиску закономерностей в очищенных данных. Анализ разделен на 4 тематических блока, которые позволят сформировать комплексное представление о рынке аналитики в 2026 году.
Блок 1. Общий обзор рынка¶
- Топ работодателей: Какие компании лидируют по количеству вакансий (ТОП-10 после консолидации брендов).
- Востребованность опыта: Какие грейды специалистов наиболее востребованы на текущем рынке.
- География поиска: Сравнение активности рынка в крупнейших хабах: Москва, Санкт-Петербург и Казань.
Блок 2. Деньги и прозрачность¶
- Прозрачность условий: В каких городах работодатели чаще готовы указывать зарплату, а где рынок остается закрытым.
- География зарплат: Расчет средней и медианной зарплаты в разрезе городов.
- Карьерный рост: Зависимость дохода от опыта.
Блок 3. Условия работы¶
- Формат и гибкость: Комплексное исследование типов занятости и графиков работы. Проверка связи между опытом специалиста и доступностью удаленного формата работы.
Блок 4. Навыки и бонус¶
- Профиль компетенций: Сравнение частоты упоминания ключевых Hard Skills (SQL, Python, BI и др.) в требованиях компаний.
- [Bonus Insight] Тайминг публикаций: Анализ активности работодателей по дням недели для определения лучшего времени для мониторинга вакансий.
# Считаем топ-10 компаний по общему количеству вакансий
top_10_companies = df['company'].value_counts().head(10).index
plot_data = df[df['company'].isin(top_10_companies)]
# Строим график
plt.figure(figsize=(12, 7))
sns.countplot(
data=plot_data,
y='company',
hue='vacancy_category',
order=top_10_companies,
palette='viridis'
)
plt.title('Топ-10 компаний по количеству вакансий (Аналитики данных vs Системный аналитик)', fontsize=15)
plt.xlabel('Количество открытых вакансий')
plt.ylabel('Компания')
plt.legend(title='Направление')
plt.tight_layout()
plt.show()
# Создаем сводную таблицу для статистики под графиком
top_10_stats = plot_data.pivot_table(
index='company',
columns='vacancy_category',
aggfunc='size',
fill_value=0
)
# Добавляем колонку с общим итогом и сортируем
top_10_stats['Всего'] = top_10_stats.sum(axis=1)
top_10_stats = top_10_stats.loc[top_10_companies] # Сохраняем порядок как на графике
# Переименовываем заголовки для красоты
top_10_stats.index.name = 'Компания'
top_10_stats.columns.name = 'Направление'
display(top_10_stats)
| Направление | Аналитик данных | Системный аналитик | Всего |
|---|---|---|---|
| Компания | |||
| СБЕР | 190 | 52 | 242 |
| Ozon | 78 | 11 | 89 |
| ГАЗПРОМ | 51 | 14 | 65 |
| МТС | 45 | 19 | 64 |
| ИЦ АЙ-ТЕКО | 26 | 35 | 61 |
| Т-Банк | 43 | 7 | 50 |
| Альфа Банк | 40 | 9 | 49 |
| ВТБ | 43 | 5 | 48 |
| RWB (Wildberries & Russ) | 34 | 12 | 46 |
| Алабуга, ОЭЗ ППТ | 29 | 7 | 36 |
Вывод¶
Анализ распределения вакансий по крупнейшим работодателям позволяет сделать несколько ключевых выводов:
- Абсолютное лидерство: СБЕР занимает первое место с колоссальным отрываом — 251 вакансия. Это почти в 3 раза превышает показатели ближайшего преследователя (Ozon — 90 вакансий) и подтверждает статус компании как главного ИТ-нанимателя.
- Диспропорция направлений: Во всех компаниях из Топ-10 спрос на Аналитиков данных существенно выше, чем на Системных аналитиков. Наиболее яркий контраст виден у Газпрома, Альфа-Банка и ВТБ, где вакансий для Data-специалистов в 4–7 раз больше.
- Специфика бизнеса: Единственная компания в списке с относительно равным балансом ролей — ИЦ АЙ-ТЕКО (32 против 25). Это подчеркивает специфику системного интегратора, где проектирование систем (Системный аналитик) так же важно, как и работа с данными (Аналитик данных).
Среди компаний с наибольшим числом вакансий можно выделить СБЕР, Ozon, Газпром. Специалисты по аналитике данных на текущий момент являются более востребованными среди лидеров рынка. Однако системная аналитика сохраняет стабильный спрос в компаниях с выраженной проектной и технической разработкой.
2. Востребованность опыта: Какие грейды специалистов наиболее востребованы на текущем рынке.¶
# Указываем правильный порядок грейдов для логики графика
plt.figure(figsize=(12, 7))
exp_order = ['Нет опыта', 'От 1 года до 3 лет', 'От 3 до 6 лет', 'Более 6 лет']
sns.countplot(
data=df,
x='exp_level',
hue='vacancy_category',
order=exp_order,
palette='magma'
)
plt.title('Распределение вакансий по требуемому опыту (Грейды)', fontsize=15)
plt.xlabel('Опыт работы')
plt.ylabel('Количество вакансий')
plt.legend(title='Направление')
plt.show()
# Создаем сводную таблицу для статистики под графиком
# Считаем количество по грейдам
exp_stats = df['exp_level'].value_counts().reindex(exp_order).reset_index()
exp_stats.columns = ['Опыт работы', 'Количество вакансий']
# Добавляем расчет доли в %
total = len(df)
exp_stats['Доля'] = exp_stats['Количество вакансий'].apply(lambda x: f"{(x/total)*100:.1f}%")
print(f"Всего в базе: {total} вакансий")
display(exp_stats.set_index('Опыт работы'))
Всего в базе: 6177 вакансий
| Количество вакансий | Доля | |
|---|---|---|
| Опыт работы | ||
| Нет опыта | 277 | 4.5% |
| От 1 года до 3 лет | 2427 | 39.3% |
| От 3 до 6 лет | 2978 | 48.2% |
| Более 6 лет | 495 | 8.0% |
Вывод¶
Распределение вакансий наглядно иллюстрирует высокий порог входа в профессию в 2026 году:
- Доминирование Middle/Senior сегмента: Более половины всех предложений (56.1%) ориентированы на специалистов с опытом работы от 3 лет и выше. Рынок сфокусирован на поиске сотрудников для решения сложных задач, требующих накопленной экспертизы.
- Дефицит позиций для старта: Новичкам без опыта доступно всего 4.3% вакансий. Это подтверждает жесткий тренд: работодатели стремятся нанимать готовых специалистов, способных выдавать результат с первых дней работы, и минимизируют затраты на обучение «с нуля».
- Основная точка входа: Категория «От 1 года до 3 лет» (39.7%) является наиболее активной зоной найма. Это показывает, что наличие даже минимального коммерческого опыта радикально (почти в 10 раз) повышает востребованность кандидата.
Рынок труда крайне требователен к практическим навыкам. Для успешного трудоустройства начинающему аналитику необходимо компенсировать отсутствие стажа сильным портфолио и кейсами, которые подтверждают владение инструментарием на реальных задачах.
3. География поиска: Сравнение активности рынка в крупнейших хабах: Москва, Санкт-Петербург и Казань.¶
# Порядок городов для графиков
city_order = ['Москва', 'Санкт-Петербург', 'Казань']
plt.figure(figsize=(12, 7))
# Рисуем распределение вакансий по target_city
sns.countplot(
data=df,
x='target_city',
hue='vacancy_category',
order=city_order,
palette='viridis'
)
plt.title('Распределение вакансий по ключевым городам', fontsize=15)
plt.xlabel('Город')
plt.ylabel('Количество вакансий')
plt.legend(title='Направление')
plt.grid(axis='y', linestyle='--', alpha=0.4)
plt.show()
# Создаем сводную таблицу для статистики под графиком
# Группируем по городу и направлению
city_stats = df.pivot_table(
index='target_city',
columns='vacancy_category',
aggfunc='size',
fill_value=0
).reindex(city_order)
# Добавляем расчеты
city_stats['Всего вакансий'] = city_stats.sum(axis=1)
city_stats['Доля от базы'] = city_stats['Всего вакансий'].apply(lambda x: f"{(x / len(df)) * 100:.1f}%")
# Добавляем названия легенд
city_stats.index.name = 'Город'
city_stats.columns.name = 'Направление'
print(f"Всего в базе: {len(df)} вакансий")
display(city_stats)
Всего в базе: 6177 вакансий
| Направление | Аналитик данных | Системный аналитик | Всего вакансий | Доля от базы |
|---|---|---|---|---|
| Город | ||||
| Москва | 2788 | 1418 | 4206 | 68.1% |
| Санкт-Петербург | 1128 | 467 | 1595 | 25.8% |
| Казань | 267 | 109 | 376 | 6.1% |
Вывод¶
Анализ распределения вакансий по ключевым городам-хабам выявил сильную централизацию рынка:
- Москва — центр притяжения: Почти 69% всех открытых вакансий сосредоточены в столице. Это подтверждает статус Москвы как главного технологического и финансового узла, где базируются головные офисы крупнейших компаний.
- Санкт-Петербург: Занимает второе место с долей 25.7%. Несмотря на значительный объем, рынок северной столицы почти в 3 раза меньше московского.
- Региональный контекст (Казань): Казань, как один из ведущих ИТ-хабов России, показывает долю в 5.4%. Важно отметить, что даже здесь спрос на Аналитиков данных в 3 раза выше, чем на Системных аналитиков.
Рынок аналитики остается преимущественно столичным. Соискателям из регионов стоит ориентироваться либо на переезд в Москву/СПб, либо на поиск вакансий с удаленным форматом работы, которые мы рассмотрим немного позже.
# Считаем индикатор: если валюта есть — ЗП указана
df['salary_is_shown'] = df['salary_currency'].notna()
# Порядок задаем вручную для красивого графика
# Группируем по хабам и считаем % (среднее значение True/False)
city_order = ['Москва', 'Санкт-Петербург', 'Казань']
transparency = (df.groupby('target_city')['salary_is_shown'].mean() * 100).reindex(city_order)
# Визуализация
plt.figure(figsize=(12, 7))
ax = transparency.plot(kind='bar', color=['#4e79a7', '#f28e2b', '#e15759'], edgecolor='black', alpha=0.8)
plt.title('Доля вакансий с указанной зарплатой', fontsize=14, pad=15)
plt.ylabel('Процент объявлений с ценой (%)')
plt.xlabel('Город')
plt.xticks(rotation=0)
plt.ylim(0, 100)
plt.grid(axis='y', linestyle='--', alpha=0.3)
# Добавляем цифры над столбцами
for i, v in enumerate(transparency):
plt.text(i, v + 2, f"{v:.1f}%", ha='center', fontweight='bold')
plt.show()
# Создаем сводную таблицу для статистики под графиком
# Группируем данные для таблицы
transp_stats = df[df['target_city'].isin(city_order)].groupby('target_city')['salary_is_shown'].agg(
Всего='count',
Указана='sum'
).reindex(city_order)
# Считаем долю и форматируем вывод
transp_stats['Доля'] = (transp_stats['Указана'] / transp_stats['Всего'] * 100).round(1)
# Оформление заголовков
transp_stats.index.name = 'Город'
transp_stats = transp_stats[['Указана', 'Всего', 'Доля']]
display(transp_stats)
| Указана | Всего | Доля | |
|---|---|---|---|
| Город | |||
| Москва | 1151 | 4206 | 27.4 |
| Санкт-Петербург | 766 | 1595 | 48.0 |
| Казань | 220 | 376 | 58.5 |
Вывод¶
Исследование показало обратную зависимость между размером рынка и его прозрачностью в вопросах оплаты:
- Москва — "рынок ожиданий": Столица оказалась самым закрытым регионом. Всего 27.9% работодателей указывают вилку в объявлении. Это говорит о том, что в Москве зарплата чаще всего определяется по результатам собеседования, исходя из опыта и навыков кандидата.
- Казань — максимум конкретики: В Казани ситуация противоположная — 62.1% вакансий имеют четко обозначенный бюджет. Региональный рынок более прямой: компании сразу заявляют возможности, чтобы быстрее привлечь подходящих специалистов.
- Санкт-Петербург — промежуточное положение: Почти в каждой второй вакансии (48.6%) указана цена, что делает рынок северной столицы значительно более предсказуемым для соискателя, чем московский.
- Столичный парадокс: Несмотря на низкую прозрачность в процентах, за счет масштаба рынка количество вакансий с открытой ценой в Москве (1184) на 21% выше, чем в Санкт-Петербурге и Казани вместе взятых (978).
Мы наблюдаем статистический парадокс: шанс найти работу с «понятным ценником» в Москве всё равно выше за счет объема предложений, хотя в процентном соотношении столичный рынок гораздо более скрытен, чем региональный.
5. География зарплат: Расчет средней и медианной зарплаты в разрезе городов.¶
Перед анализом уровня доходов необходимо проверить распределение валют. Это позволит понять, насколько значима доля вакансий в иностранной валюте и нужно ли учитывать их при расчете средних показателей.
# Проверяем распределение валют среди вакансий, где указана ЗП
currency_stats = df['salary_currency'].value_counts().reset_index()
currency_stats.columns = ['Валюта', 'Количество']
display(currency_stats)
| Валюта | Количество | |
|---|---|---|
| 0 | RUR | 2091 |
| 1 | USD | 35 |
| 2 | EUR | 9 |
| 3 | BYR | 1 |
| 4 | KGS | 1 |
Резюме по валютам: Как мы видим, подавляющее большинство вакансий с указанным доходом (более 97%) номинированы в рублях (RUR). Доля иностранных валют (USD, EUR, BYR) суммарно составляет около 2.5%.
Учитывая незначительную погрешность, в дальнейшем анализе уровня зарплат мы сосредоточимся исключительно на рублевых выплатах. Это позволит избежать искажений, связанных с волатильностью курсов.
# 1. Расчет средней ЗП
df['salary_mean'] = df[['salary_from', 'salary_to']].mean(axis=1)
# 2. Фильтрация данных (наличие валюты и рассчитанной ЗП)
df_money = df[df['salary_currency'].notna() & df['salary_mean'].notna()]
# 3. Агрегация данных для таблицы
salary_report = df_money.groupby(['target_city', 'vacancy_category'])['salary_mean'].agg(['mean', 'median', 'count']).round(0)
salary_report.index.names = ['Город', 'Направление']
# Сразу подготавливаем таблицу для отображения в нужном порядке городов
final_table = salary_report.reindex(['Москва', 'Санкт-Петербург', 'Казань'], level=0)
# 4. Визуализация разброса
plt.figure(figsize=(12, 7))
sns.boxplot(data=df_money, x='target_city', y='salary_mean', hue='vacancy_category',
order=['Москва', 'Санкт-Петербург', 'Казань'], palette='Set2')
plt.legend(title='Направление')
plt.title('Разброс предлагаемых зарплат по городам и направлениям', fontsize=15)
plt.ylabel('Сумма (в единицах валюты вакансии)')
plt.xlabel('Город')
plt.grid(axis='y', alpha=0.3)
# Команда plt.show() "закрывает" график и выводит его на экран
plt.show()
# Вывод таблицы под графиком
display(final_table)
| mean | median | count | ||
|---|---|---|---|---|
| Город | Направление | |||
| Москва | Аналитик данных | 168451.0 | 150000.0 | 604 |
| Системный аналитик | 175399.0 | 150000.0 | 547 | |
| Санкт-Петербург | Аналитик данных | 132088.0 | 120000.0 | 510 |
| Системный аналитик | 153639.0 | 131000.0 | 256 | |
| Казань | Аналитик данных | 134650.0 | 105250.0 | 150 |
| Системный аналитик | 150036.0 | 130000.0 | 70 |
Вывод¶
Сравнительный анализ зарплат в разрезе городов и направлений позволяет выделить несколько ключевых моментов:
- Доплата за специализацию: Практически во всех городах Системные аналитики получают больше, чем Аналитики данных. В Москве разрыв в среднем составляет около 10 000 руб., а в Санкт-Петербурге медиана у Системного аналитика выше на 15 000 руб. Это подтверждает, что рынок готов платить больше за понимание технического устройства систем и интеграций.
- Среднее vs Медиана: Во всех группах среднее значение заметно выше медианы. Это происходит из-за небольшого числа вакансий с очень высокими зарплатами (выбросов), которые завышают общую статистику.
- Ориентир для соискателя: Для планирования бюджета лучше смотреть на медиану — это сумма, которую получает большинство специалистов. При этом высокое среднее значение указывает на достойный «потолок» в профессии, особенно в столицах.
Системная аналитика сейчас выглядит финансово чуть более выгодной в Москве и Петербурге. При этом Москва остается единственным городом, где медиана по обоим направлениям держится на уровне 150 000 руб.
print(df.columns.tolist())
['id', 'name', 'published_date', 'target_city', 'target_query', 'city', 'company', 'exp_level', 'job_type', 'work_schedule', 'salary_from', 'salary_to', 'salary_currency', 'requirements', 'vacancy_category', 'skill_SQL', 'skill_Python', 'skill_Spark', 'skill_Pandas', 'skill_Excel', 'skill_Power BI', 'skill_Tableau', 'skill_Superset', 'skill_Airflow', 'skill_ETL', 'skill_ClickHouse', 'skill_A/B тесты', 'skill_Английский язык', 'skill_Git', 'salary_is_shown', 'salary_mean']
6. Карьерный рост: Зависимость дохода от опыта.¶
# 1. ВОССТАНОВЛЕНИЕ ДАННЫХ (встраиваем создание категорий)
bins = [0, 100000, 200000, 300000, float('inf')]
labels = ['Меньше 100 тысяч', 'От 100 тысяч до 200 тысяч', 'От 200 тысяч до 300 тысяч', 'Больше 300 тысяч']
# Создаем категории на основе salary_mean
df['salary_cat'] = pd.cut(df['salary_mean'], bins=bins, labels=labels, right=False)
# Преобразуем в строку и заполняем пустоты (NaN) нашей категорией
df['salary_cat'] = df['salary_cat'].astype(str).replace('nan', 'ЗП не указана')
# 2. ПОДГОТОВКА ДАННЫХ ДЛЯ ГРАФИКА
cat_order = ['ЗП не указана', 'Меньше 100 тысяч', 'От 100 тысяч до 200 тысяч',
'От 200 тысяч до 300 тысяч', 'Больше 300 тысяч']
exp_order = ['Нет опыта', 'От 1 года до 3 лет', 'От 3 до 6 лет', 'Более 6 лет']
colors = ['#f8f9fa', '#ddecff', '#5a5a5a', '#849697', '#d9534f']
# Общая группировка
full_stat = df.groupby(['vacancy_category', 'exp_level', 'salary_cat']).size().unstack(fill_value=0)
# Переименовываем уровни индексов и колонок
full_stat.index.names = ['Направление', 'Опыт']
full_stat.columns.name = 'Зарплата'
# Расчет процентов для графиков
full_stat_pct = full_stat.div(full_stat.sum(axis=1), axis=0) * 100
# 3. ВИЗУАЛИЗАЦИЯ
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(18, 7), sharey=True)
plt.subplots_adjust(wspace=0.05)
# График1: Аналитик данных
da_data = full_stat_pct.loc['Аналитик данных'].reindex(exp_order)[cat_order]
da_data.plot(kind='barh', stacked=True, ax=ax1, color=colors, edgecolor='white', width=0.8, legend=False)
ax1.set_title('АНАЛИТИК ДАННЫХ', fontsize=14, fontweight='bold', pad=15)
ax1.set_xlabel('Процентное соотношение (%)')
ax1.set_ylabel('Опыт')
# График2: Системный аналитик
sa_data = full_stat_pct.loc['Системный аналитик'].reindex(exp_order)[cat_order]
sa_data.plot(kind='barh', stacked=True, ax=ax2, color=colors, edgecolor='white', width=0.8, legend=False)
ax2.set_title('СИСТЕМНЫЙ АНАЛИТИК', fontsize=14, fontweight='bold', pad=15)
ax2.set_xlabel('Процентное соотношение (%)')
ax2.set_ylabel('')
# Добавляем проценты
for ax in [ax1, ax2]:
for p in ax.patches:
width = p.get_width()
if width > 4:
x = p.get_x() + width / 2
y = p.get_y() + p.get_height() / 2
ax.annotate(f'{width:.1f}%', (x, y), ha='center', va='center',
fontsize=10, color='#333333', fontweight='500')
# Общая легенда
fig.legend(cat_order, loc='lower center', ncol=5, bbox_to_anchor=(0.5, -0.05), frameon=False, fontsize=11)
plt.suptitle('РАСПРЕДЕЛЕНИЕ ЗАРПЛАТНЫХ КАТЕГОРИЙ ПО ОПЫТУ', fontsize=18, y=1.05, fontweight='bold')
plt.show()
display(full_stat)
| Зарплата | Больше 300 тысяч | ЗП не указана | Меньше 100 тысяч | От 100 тысяч до 200 тысяч | От 200 тысяч до 300 тысяч | |
|---|---|---|---|---|---|---|
| Направление | Опыт | |||||
| Аналитик данных | Более 6 лет | 22 | 251 | 5 | 21 | 27 |
| Нет опыта | 5 | 90 | 86 | 26 | 6 | |
| От 1 года до 3 лет | 11 | 1037 | 223 | 340 | 57 | |
| От 3 до 6 лет | 43 | 1541 | 44 | 192 | 156 | |
| Системный аналитик | Более 6 лет | 20 | 119 | 5 | 5 | 20 |
| Нет опыта | 1 | 18 | 27 | 13 | 5 | |
| От 1 года до 3 лет | 19 | 316 | 112 | 270 | 42 | |
| От 3 до 6 лет | 39 | 668 | 19 | 153 | 123 |
Вывод¶
Анализ структуры зарплатных предложений в зависимости от стажа выявил два ключевых тренда:
- Падение прозрачности с ростом опыта: Если у новичков зарплата открыта в 60–70% случаев, то к уровню «3–6 лет» ситуация меняется зеркально: более 75% вакансий уходят в зону "ЗП не указана". Чем выше экспертность, тем чаще доход становится предметом индивидуальных переговоров.
- Ускоренный рост Системных аналитиков: Направление Системный аналитик показывает более прогрессивный рывок в доходах. Уже на этапе «1–3 года» доля вакансий с чеком 100–200 тыс. руб. у них составляет 37.5%, что почти в два раза выше, чем у Аналитиков данных (19.8%).
- Стартовые условия: Для обеих ролей основной доход на старте — до 100 тыс. руб. (~40% вакансий). Однако у Системных аналитиков даже без опыта есть шанс (6%) зайти в категорию 200–300 тыс. руб., в то время как для Аналитиков данных этот сценарий практически исключен.
Системным аналитикам предлагают более быстрый финансовый лифт на средних дистанциях (1–3 года). При этом для всех направлений характерно закрытие информации о деньгах по мере продвижения к Senior-позициям.
Напишем функцию применимую для типа занятости и графика работы.
# Определяем правильный порядок грейдов для графиков
exp_order = ['Нет опыта', 'От 1 года до 3 лет', 'От 3 до 6 лет', 'Более 6 лет']
# Функция для построения сгруппированного графика
def plot_exp_stats(df, column_name, title_name, legend_title):
# Группируем данные по грейду и нужному признаку
# unstack переводит значения признака в столбцы
stats = df.groupby(['exp_level', column_name]).size().unstack(fill_value=0)
# Переводим в проценты внутри каждого грейда
pct = stats.div(stats.sum(axis=1), axis=0) * 100
# Сортируем по списку опыта
pct = pct.reindex(exp_order)
# Визуализация
ax = pct.plot(kind='bar', figsize=(12, 7), width=0.8, color=sns.color_palette('pastel'))
plt.title(f'{title_name} в зависимости от опыта', fontsize=15, pad=20)
plt.ylabel('Доля вакансий (%)')
plt.xlabel('Опыт работы (Грейд)')
plt.xticks(rotation=0)
plt.legend(title=legend_title, bbox_to_anchor=(1.05, 1), loc='upper left')
plt.grid(axis='y', alpha=0.3)
# Подписи процентов
for p in ax.patches:
height = p.get_height()
if height > 1:
ax.annotate(f'{height:.1f}%', (p.get_x() + p.get_width()/2., height),
ha='center', va='bottom', fontsize=9, xytext=(0, 5), textcoords='offset points')
plt.show()
# Оформление таблицы для вывода
pct.index.name = 'Опыт'
pct.columns.name = legend_title
display(pct.round(1))
plot_exp_stats(df, 'job_type', 'Изменение типа занятости', 'Тип занятости')
| Тип занятости | Полная занятость | Проектная работа | Частичная занятость |
|---|---|---|---|
| Опыт | |||
| Нет опыта | 87.4 | 5.1 | 7.6 |
| От 1 года до 3 лет | 97.2 | 0.7 | 2.1 |
| От 3 до 6 лет | 98.3 | 1.1 | 0.7 |
| Более 6 лет | 98.0 | 1.6 | 0.4 |
Вывод¶
Анализ типов занятости подтверждает стабильность и "процессный" характер работы в аналитике:
- Доминирование Full-time: Подавляющее большинство вакансий (87% – 98%) на всех этапах карьеры — это полная занятость. Рынок аналитики в 2026 году ориентирован на долгосрочное сотрудничество, а не на разовые задачи.
- Стажировочный фильтр: У кандидатов без опыта наблюдается самый высокий процент частичной занятости (10.2%). Это явно указывает на наличие программ стажировок, ориентированных на студентов и позволяющих совмещать работу с учебой.
- Игнорирование фриланса: Проектная работа остается нишевой историей (всего 1.4% даже для Senior-грейдов). Аналитика требует глубокого погружения в бизнес-контекст компании, поэтому временные контракты здесь практически не востребованы.
Аналитик — это штатный сотрудник. Если вы планируете карьеру в этой сфере, стоит ориентироваться на полную занятость; формат проектного фриланса здесь практически не развит.
График работы и связь между опытом специалиста и доступностью удаленного формата работы.¶
# График работы
plot_exp_stats(df, 'work_schedule', 'Изменение графика работы', 'График работы')
| График работы | Вахтовый метод | Гибкий график | Полный день | Сменный график | Удаленная работа |
|---|---|---|---|---|---|
| Опыт | |||||
| Нет опыта | 0.4 | 6.9 | 68.2 | 0.4 | 24.2 |
| От 1 года до 3 лет | 0.0 | 0.6 | 68.9 | 0.5 | 30.0 |
| От 3 до 6 лет | 0.0 | 0.3 | 65.2 | 0.1 | 34.4 |
| Более 6 лет | 0.0 | 0.2 | 57.6 | 0.0 | 42.2 |
Вывод¶
Анализ графиков работы подтверждает прямую зависимость между стажем специалиста и доступностью дистанционного формата:
- Офис как база для старта: У новичков («Нет опыта») преобладает работа в офисе (67.8%). Это связано с необходимостью очного менторства: компаниям важно, чтобы начинающий специалист быстрее погрузился в процессы под присмотром опытных коллег.
- Рост автономности: Первый заметный переход к удаленному формату (30.5%) происходит при получении опыта от 1 до 3 лет. Это сигнал от рынка: как только специалист доказывает способность решать задачи самостоятельно, потребность в ежедневном контроле в офисе снижается.
- Удаленка для экспертов: Для профи с опытом более 6 лет доля дистанционной работы достигает максимума (44.0%). На этом уровне экспертиза становится критически важной, и работодатели чаще соглашаются на условия кандидата, чтобы привлечь редкого специалиста.
- Гибкость для студентов: Относительно высокая доля гибкого графика у новичков (8.0%) указывает на развитие программ стажировок. Для опытных специалистов этот показатель практически обнуляется — эксперт должен быть доступен в рабочие часы для взаимодействия с командой.
Удаленная работа в аналитике напрямую коррелирует с уровнем ответственности и подтвержденным опытом. Начинающим специалистам стоит ориентироваться на офис или гибрид для эффективного обучения, в то время как опытные кадры могут рассчитывать на удаленный формат почти в половине вакансий.
# Настройка данных
skill_columns = [col for col in df.columns if col.startswith('skill_')]
skills_short_names = [col.replace('skill_', '') for col in skill_columns]
da_skills = df[df['vacancy_category'] == 'Аналитик данных'][skill_columns].sum()
sa_skills = df[df['vacancy_category'] == 'Системный аналитик'][skill_columns].sum()
# Функция для бублика
def plot_clean_donut(data, title, ax):
# Оставляем только те навыки, которые > 0 для этого графика
data = data[data > 0].sort_values(ascending=False)
colors = sns.color_palette("tab20", len(data))
# Строим диаграмму
wedges, texts, autotexts = ax.pie(
data,
labels=data.index,
autopct=lambda p: f'{p:.1f}%' if p > 3 else '', # Скрываем текст меньше 3%
startangle=140,
colors=colors,
pctdistance=0.75,
labeldistance=1.1,
textprops={'fontsize': 10}
)
# Делаем дырку в бублике
centre_circle = plt.Circle((0,0), 0.45, fc='white')
ax.add_artist(centre_circle)
ax.set_title(title, fontsize=14, fontweight='bold', pad=20)
# Визуализация
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(20, 10))
plot_clean_donut(da_skills, 'Аналитик данных', ax1)
plot_clean_donut(sa_skills, 'Системный аналитик', ax2)
plt.tight_layout()
plt.show()
# Объедененный анализ связок
def get_market_bundle(skill1, skill2):
# Считаем по всему датафрейму
count = len(df[(df[f'skill_{skill1}'] == 1) & (df[f'skill_{skill2}'] == 1)])
return round((count / len(df)) * 100, 2)
market_bundles = [
('SQL', 'Python', 'Автоматизация и работа с БД'),
('SQL', 'Excel', 'Классический фундамент'),
('SQL', 'A/B тесты', 'Продуктовая аналитика'),
('Python', 'Spark', 'Работа с Big Data'),
('SQL', 'Git', 'Командная разработка / Analytics Engineering'),
('ETL', 'ClickHouse', 'Высоконагруженные хранилища')
]
bundle_results = []
for s1, s2, name in market_bundles:
bundle_results.append({
'Связка навыков': f'{s1} + {s2}',
'Контекст': name,
'Доля': get_market_bundle(s1, s2)
})
market_bundle_df = pd.DataFrame(bundle_results).sort_values(by='Доля', ascending=False)
display(market_bundle_df)
| Связка навыков | Контекст | Доля | |
|---|---|---|---|
| 0 | SQL + Python | Автоматизация и работа с БД | 2.96 |
| 1 | SQL + Excel | Классический фундамент | 1.33 |
| 3 | Python + Spark | Работа с Big Data | 0.31 |
| 4 | SQL + Git | Командная разработка / Analytics Engineering | 0.28 |
| 2 | SQL + A/B тесты | Продуктовая аналитика | 0.15 |
| 5 | ETL + ClickHouse | Высоконагруженные хранилища | 0.05 |
Вывод¶
Анализ востребованных инструментов и их сочетаний в 2026 году показывает четкое разделение ролей:
- Базовый стек: SQL и Excel остаются фундаментом. На них приходится более 55% всех упоминаний инструментов. Это обязательный минимум для входа в профессию вне зависимости от направления.
- Специфика ролей:
- Аналитики данных: Делают упор на визуализацию (Power BI, Tableau) и автоматизацию обработки данных (Python, Pandas).
- Системные аналитики: Чаще работают с командной разработкой (Git — 22.5%) и англоязычной документацией. Python требуется значительно реже (около 7%).
- Популярные связки: Сочетание SQL + Python (2.76%) стало встречаться чаще, чем традиционное SQL + Excel (1.27%). Это подтверждает растущий запрос рынка на навыки автоматизации рутинных задач.
- Особенности данных: Невысокие абсолютные проценты в связках объясняются тем, что в краткие описания вакансий попадают только наиболее критичные требования. При этом общие пропорции и лидеры навыков остаются репрезентативными.
SQL — универсальный инструмент. Выбор между изучением Python (для Аналитика данных) или Git/Документации (для Системного аналитика) определяет дальнейший вектор развития специалиста.
9. [Bonus Insight] Тайминг публикаций: Анализ активности работодателей по дням недели для определения лучшего времени для мониторинга вакансий.¶
# Приводим к формату даты (если еще не сделано)
df['published_date'] = pd.to_datetime(df['published_date'])
# Извлекаем день недели и задаем порядок
df['day_name'] = df['published_date'].dt.day_name()
days_order = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
days_ru = ['Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб', 'Вс']
# Подготовка данных
weekly_data = df['day_name'].value_counts().reindex(days_order)
values = weekly_data.values
# Формируем леденцовую диаграмму (Lollipop Chart)
plt.figure(figsize=(12, 7))
# Рисуем палочки
plt.vlines(x=days_ru, ymin=0, ymax=values, color='#d3d3d3', alpha=0.6, linewidth=2)
# Рисуем точки
# Акцентируем внимание на Пятнице (индекс 4) контрастным цветом
colors = ['#1f77b4' if x == 'Пт' else '#A0C4FF' for x in days_ru]
plt.scatter(days_ru, values, color=colors, s=180, edgecolors='black', zorder=3)
# Оформление
plt.title('Когда чаще всего публикуют вакансии?', fontsize=16, fontweight='bold', pad=25)
plt.ylabel('Количество вакансий', fontsize=12)
plt.ylim(0, max(values) + 150) # Запас сверху для подписей
plt.grid(axis='y', linestyle='--', alpha=0.3)
# Добавляем цифры над леденцами
for i, val in enumerate(values):
plt.text(i, val + 40, f'{int(val)}', ha='center', va='bottom',
fontsize=11, fontweight='bold', color='#333333')
# Убираем верхнюю и правую рамки
sns.despine()
plt.tight_layout()
plt.show()
Вывод¶
Анализ дат публикации вакансий позволяет определить наиболее активные периоды обновления рынка:
- Пик активности в пятницу: Наибольшее количество объявлений публикуется в пятницу (1313 вакансий). Это на 30–40% превышает средние показатели других будних дней.
- Стабильность в будни: С понедельника по четверг интенсивность публикаций сохраняется на уровне примерно 900 вакансий в день.
- Спад в выходные: В субботу и воскресенье количество новых предложений минимально (560–640 вакансий).
Пятница — ключевой день для обнаружения новых позиций. Однако, учитывая механику работы HR-платформ (где новые отклики вытесняют старые), оптимальная стратегия — откликаться либо сразу после публикации в пятницу, либо в первой половине понедельника, чтобы оставаться в верхней части списка неразобранных резюме.
Итоговое резюме¶
Данное исследование представляет собой полный цикл анализа данных (End-to-End): от автоматизированного сбора сырой информации через API до формирования стратегических выводов.
Методология проекта¶
- Сбор данных: Разработка парсера для взаимодействия с API HH.ru.
- Data Cleaning: Очистка дубликатов, нормализация компаний, обработка пропусков и HTML-тегов.
- EDA & Визуализация: Анализ распределений и создание дашбордов (Matplotlib, Seaborn).
Ключевые выводы исследования¶
1. Обзор рынка и география¶
- Лидеры спроса: Компании СБЕР, Ozon и Газпром формируют основной объем вакансий. Специалисты по Data Analytics сейчас более востребованы количественно, тогда как System Analytics сохраняет стабильный спрос в проектной разработке.
- Локация: Рынок остается столичным (Москва/СПб). Соискателям из регионов критически важно ориентироваться на удаленный формат или релокацию.
- Опыт: Рынок требователен к стажу. Начинающим специалистам необходимо компенсировать отсутствие опыта сильным портфолио с реальными кейсами.
2. Финансы и прозрачность¶
- Зарплатный парадокс: В Москве шанс найти вакансию с открытой зарплатой выше за счет объема рынка, хотя в процентах столичный рынок более скрытен, чем региональный.
- Уровень дохода: Системная аналитика финансово выгоднее на дистанции 1–3 года («быстрый лифт»). Москва — единственный город, где медиана по обоим направлениям держится на уровне 150 000 руб.
- Senior-сегмент: Информация о доходе практически всегда скрывается по мере роста позиции до уровня Senior.
3. Условия и формат работы¶
- Занятость: Аналитик — это штатная роль. Формат проектного фриланса в этой сфере практически отсутствует, стоит ориентироваться на Full-time.
- Удаленка: Возможность работать из дома напрямую коррелирует с опытом. Новичкам чаще предлагают офис или гибрид для онбординга, в то время как опытным кадрам удаленный формат доступен почти в 50% вакансий.
4. Профиль компетенций¶
- База: SQL — универсальный и обязательный инструмент для обеих ролей.
- Специализация: Вектор развития определяется выбором между Python (Data Analytics) или Git и документацией (System Analytics).
Бонус-инсайт: Тайминг публикаций¶
Пятница — пиковый день для новых вакансий. Стратегия отклика: Чтобы не затеряться в списке, откликайтесь либо сразу в пятницу, либо в первой половине понедельника. Это гарантирует, что ваше резюме будет в топе неразобранных у HR-менеджера.