Физтех.Статистика
Скачать ipynb
Введение в анализ данных¶
Домашнее задание 10. Анализ вакансий.¶
Правила, прочитайте внимательно:
- Выполненную работу нужно отправить телеграм-боту
@miptstats_ds24_bot
. Для начала работы с ботом каждый раз отправляйте/start
. Дождитесь подтверждения от бота, что он принял файл. Если подтверждения нет, то что-то не так. Работы, присланные иным способом, не принимаются. - Дедлайн см. в боте. После дедлайна работы не принимаются кроме случаев наличия уважительной причины.
- Прислать нужно ноутбук в формате
ipynb
и полученные данные (подробности далее). Если вы строите интерактивные графики, их стоит прислать в формате html. - Следите за размером файлов. Бот не может принимать файлы весом более 20 Мб. Если файл получается больше, заранее разделите его на несколько.
- Будьте внимательны при работе со сбором данных. Ответственность за корректность ваших действий лежит на вас. Не нагружайте сервера, делайте паузы между запросами. Как следствие, начинайте выполнять задание заранее. Если вас где-то забаннили и т.п., то это не является уважительной причиной продления дедлайна.
- Выполнять задание необходимо полностью самостоятельно. При обнаружении списывания все участники списывания будут сдавать устный зачет.
- Решения, размещенные на каких-либо интернет-ресурсах, не принимаются. Кроме того, публикация решения в открытом доступе может быть приравнена к предоставлении возможности списать.
- Для выполнения задания используйте этот ноутбук в качестве основы, ничего не удаляя из него. Можно добавлять необходимое количество ячеек.
- Комментарии к решению пишите в markdown-ячейках.
- Выполнение задания (ход решения, выводы и пр.) должно быть осуществлено на русском языке.
- Если код будет не понятен проверяющему, оценка может быть снижена.
- Никакой код из данного задания при проверке запускаться не будет. Если код студента не выполнен, недописан и т.д., то он не оценивается.
Баллы за задание:
Сложная часть (учитывается только в основной части курса, необходимо на "отл"):
- Задача 1 — 70 баллов
Факультативная часть (учитывается только в факультативной части курса):
- Задача 2 — 30 баллов
- Задача 3 — 70 баллов
Внимание! Указанные баллы являются бонусными. Они не учитываются в максимальных суммах баллов в знаменателе при вычислении процента выполненных заданий. Но все полученные вами баллы будут учтены в числителе. Тем самым, выполняя или не выполняя домашку, вы не сможете понизить оценку, но сможете ее повысить.
# Bot check
# HW_ID: fpmi_ad10
# Бот проверит этот ID и предупредит, если случайно сдать что-то не то.
# Status: not final
# Перед отправкой в финальном решении удали "not" в строчке выше.
# Так бот проверит, что ты отправляешь финальную версию, а не промежуточную.
# Никакие значения в этой ячейке не влияют на факт сдачи работы.
import requests
from time import sleep
import json
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
sns.set(style="whitegrid", font_scale=1.3, palette="Set2")
Второй курс — самое время задуматься о будущей профессии и проанализировать существующие предложения. Дело тут даже не в том, чтобы найти интересную стажировку. В первую очередь сейчас стоит подумать о том, в какую сторону развиваться дальше. Например, если вы хотите работать в какой-либо конкретной профессии, то наверняка стоит развивать какие-то определенные навыки, и даже выбрать подходящую кафедру. Анализ существующих вакансий поможет определить, какие навыки вам нужны.
Внимание! В первую очередь задание призвано помочь вам понять, какие навыки стоит развивать, и может быть даже выбрать подходящую кафедру. Однако, не стоит идти на работу/стажировку раньше времени. Даже только летнюю, абсолютное большинство людей не могут работать круглый год без перерыва. У всех из вас 3 курс достаточно нагруженный, а на DS-потоке нагрузка с первой недели сентября. И если вы идете на стажировку, то каникул у вас может просто не остаться. Даже если вам сейчас/летом/в сентябре кажется "я же справлюсь", к ноябрю-декабрю с большой вероятностью вы выдохнетесь. Таких примеров очень много. Не все, кто-то успешно справляется совмещать работу и учебу, но таких очень мало. Берегите себя и свое здоровье :)
Задание предполагает вариативность исследуемых данных. Вы можете выбрать один из следующих вариантов.
- Стандартный вариант — проанализировать вакансии на сайте hh.ru с использованием официального API. Далее приведен пример работы с этим API. Если вы не достаточно уверены в своих силах, рекомендуется выбрать этот вариант.
- Разобраться с API других сервисов по поиску вакансий, например, Хабр.Карьера или SuperJob.
- Извлечение данных с помощью парсинга HTML напрямую некоторых сайтов. Например, вы можете попробовать напрямую распарсить пул вакансий из тех источников, которые не предоставляют API. Внимание! Обращайте внимание на пользовательские соглашения и на эти рекомендации.
- Комбинирование нескольких подходов. В этом случае нужно понимать, как находить одинаковые вакансии из разных источников для избежания их двойного учета.
- Можно также дополнительно брать архивные данные из недавнего прошлого, например, из этого соревнования.
Перед выполнением задания ознакомьтесь с материалом о сборе данных из открытых источников.
Для получения максимального балла за задание достаточно выполнить все задание по стандартному варианту. Альтернативные варианты, даже более сложные, не дают больше баллов, чем максимальное количество баллов по стандартному варианту.
Работа в некоторой степени творческая, поэтому конкретные детали решения в основном остаются на усмотрение автора решения. Например, если в вакансии зарплата укзана "от ..." или "до ...", то вы сами решаете, как это обрабатывать, но не забывайте про четкую аргументацию. Не забывайте также заглядывать в презентацию по выполнению и оформлению домашних заданий с занятия 2.
Справка по работе с API сервиса hh.ru.¶
Внимание! При работе с API не забывайте делать паузы между запросами, чтобы не задудосить сервер. Если вас заблокируют, это не будет являться уважительной причиной переноса дедлайна.
Мы будем работать только с вакансиями. Для этого не требуется регистрироваться и получать токен. Ниже приведен краткий пример работы с API. Подробное описание работы с вакансиями, включая параметры запросов и формат ответа можно почитать в документации.
Например, мы хотим найти вакансии по запросу Data Scientist
в Москве. Тогда первую страницу поиска из 10 вакансий на страницу мы можем получить с запроса к API:
URL = "https://api.hh.ru/vacancies"
params = {
"text": "Data Scientist",
"area": 1,
"page": 0,
"per_page": 10,
}
req = requests.get(URL, params)
data = json.loads(req.content.decode())
Если все прошло успешно, полученный словарь будет иметь следующие ключи
data.keys()
dict_keys(['items', 'found', 'pages', 'page', 'per_page', 'clusters', 'arguments', 'fixes', 'suggests', 'alternate_url'])
Можем посмотреть на краткое описание первой вакансии
data["items"][0]
{'id': '98269481', 'premium': False, 'name': 'Data Scientist / ML-инженер', 'department': None, 'has_test': False, 'response_letter_required': False, 'area': {'id': '1', 'name': 'Москва', 'url': 'https://api.hh.ru/areas/1'}, 'salary': None, 'type': {'id': 'open', 'name': 'Открытая'}, 'address': None, 'response_url': None, 'sort_point_distance': None, 'published_at': '2024-05-02T17:45:01+0300', 'created_at': '2024-05-02T17:45:01+0300', 'archived': False, 'apply_alternate_url': 'https://hh.ru/applicant/vacancy_response?vacancyId=98269481', 'show_logo_in_search': None, 'insider_interview': None, 'url': 'https://api.hh.ru/vacancies/98269481?host=hh.ru', 'alternate_url': 'https://hh.ru/vacancy/98269481', 'relations': [], 'employer': {'id': '6382', 'name': 'Медиалогия', 'url': 'https://api.hh.ru/employers/6382', 'alternate_url': 'https://hh.ru/employer/6382', 'logo_urls': {'original': 'https://img.hhcdn.ru/employer-logo-original/867798.png', '90': 'https://img.hhcdn.ru/employer-logo/3912067.png', '240': 'https://img.hhcdn.ru/employer-logo/3912068.png'}, 'vacancies_url': 'https://api.hh.ru/vacancies?employer_id=6382', 'accredited_it_employer': False, 'trusted': True}, 'snippet': {'requirement': 'Знание Python и библиотек для работы с данными и классическим ML (numpy, pandas, sklearn, catboost и др.). Желателен опыт создания...', 'responsibility': 'Создание моделей для задач NLP и CV. Доработка и улучшение существующих моделей. Анализ данных из социальных сетей: классификация, кластеризация, определение...'}, 'contacts': None, 'schedule': {'id': 'remote', 'name': 'Удаленная работа'}, 'working_days': [], 'working_time_intervals': [], 'working_time_modes': [], 'accept_temporary': False, 'professional_roles': [{'id': '165', 'name': 'Дата-сайентист'}], 'accept_incomplete_resumes': False, 'experience': {'id': 'between1And3', 'name': 'От 1 года до 3 лет'}, 'employment': {'id': 'full', 'name': 'Полная занятость'}, 'adv_response_url': None, 'is_adv_vacancy': False, 'adv_context': None}
Сколько всего найдено вакансий
data["found"]
362
Количество страниц в результатах поиска
data["pages"]
37
Из результатов можем сделать удобную таблицу, причем в дальнейшем можно оставить только те колонки, которые необходимы для анализа.
df = pd.json_normalize(data["items"])
df.head()
id | premium | name | department | has_test | response_letter_required | salary | address | response_url | sort_point_distance | ... | address.metro.station_id | address.metro.line_id | address.metro.lat | address.metro.lng | address.metro_stations | address.id | department.id | department.name | insider_interview.id | insider_interview.url | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 98263959 | False | Logistics Manager | NaN | False | False | None | NaN | None | None | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
1 | 97153868 | False | Junior Data Scientist (Ranking&Search) | NaN | True | False | None | NaN | None | None | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
2 | 98214631 | False | Data Scientist | NaN | False | False | None | NaN | None | None | ... | 5.36 | 5 | 55.728994 | 37.622533 | [{'station_name': 'Добрынинская', 'line_name':... | 1079022 | NaN | NaN | NaN | NaN |
3 | 98269481 | False | Data Scientist / ML-инженер | NaN | False | False | None | NaN | None | None | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
4 | 98088762 | False | Junior data scientist (модели кредитного риска) | NaN | False | False | None | NaN | None | None | ... | 2.512 | 2 | 55.695000 | 37.664167 | [{'station_name': 'Технопарк', 'line_name': 'З... | 602591 | 80-80-expert | Альфа-Банк. Центральный офис | 32631 | https://hh.ru/interview/32631?employerId=80 |
5 rows × 73 columns
Для получения полного описания вакансии потребуется задать отдельный запрос, используя ее id
.
vacancy = df["id"].iloc[0]
vacancy_url = f"https://api.hh.ru/vacancies/{vacancy}"
req = requests.get(vacancy_url)
vacancy_info = json.loads(req.content.decode())
vacancy_info
{'id': '98269481', 'premium': False, 'billing_type': {'id': 'standard', 'name': 'Стандарт'}, 'relations': [], 'name': 'Data Scientist / ML-инженер', 'insider_interview': None, 'response_letter_required': False, 'area': {'id': '1', 'name': 'Москва', 'url': 'https://api.hh.ru/areas/1'}, 'salary': None, 'type': {'id': 'open', 'name': 'Открытая'}, 'address': None, 'allow_messages': True, 'experience': {'id': 'between1And3', 'name': 'От 1 года до 3 лет'}, 'schedule': {'id': 'remote', 'name': 'Удаленная работа'}, 'employment': {'id': 'full', 'name': 'Полная занятость'}, 'department': None, 'contacts': None, 'description': '<p>Медиалогия разрабатывает высоконагруженные системы, которые в режиме реального времени сканируют весь текстовый сегмент Интернета (100+ млн. сообщений в сутки, 1.7 млрд. метрик) и, используя уникальные технологии лингвистического анализа и компьютерного зрения, позволяют осуществлять мгновенный анализ упоминаний наших клиентов в соц.сетях, блогах, форумах и управлять их репутацией.</p> <p>Наша команда активно растет и сейчас мы в поиске <strong>Data Scientist / ML-инженер (Middle)</strong><strong>.</strong></p> <p><strong>Вам предстоит:</strong></p> <ul> <li>создание моделей для задач NLP и CV;</li> <li>доработка и улучшение существующих моделей;</li> <li>анализ данных из социальных сетей: классификация, кластеризация, определение сущностей, выявление аномалий;</li> <li>проведение экспериментов на "больших данных" и обработка результатов;</li> <li>построение и тестирование гипотез.</li> </ul> <p><strong>Наши пожелания к будущему коллеге:</strong></p> <ul> <li>знание Python и библиотек для работы с данными и классическим ML (numpy, pandas, sklearn, catboost и др.);</li> <li>желателен опыт создания моделей машинного обучения на TensorFlow, PyTorch;</li> <li>умение работать с неструктурированными контентом, правильно оценивать качество моделей;</li> <li>желателен опыт работы с большими данными (Spark, Hadoop).</li> <li>умение работать в команде, хорошие коммуникативные навыки;</li> <li>желание активно развиваться и браться за самые сложные задачи.</li> </ul> <p><strong>Мы предлагаем:</strong></p> <ul> <li> <p>работу в аккредитованной IT-компании со всеми преимуществами;</p> </li> <li>белую ЗП, официальное оформление по ТК РФ;</li> <li>ДМС с хорошим выбором клиник и международной страховкой;</li> <li>возможность посещения профильных мероприятий и карьерное развитие;</li> <li>гибкое начало рабочего дня;</li> <li>удаленный формат работы;</li> <li>активное развитие в сильной data science команде.</li> </ul>', 'branded_description': None, 'vacancy_constructor_template': None, 'key_skills': [{'name': 'Python'}, {'name': 'ML'}, {'name': 'NLP'}, {'name': 'Deep Learning'}, {'name': 'Машинное обучение'}, {'name': 'Pandas'}, {'name': 'Numpy'}, {'name': 'Hadoop'}, {'name': 'Spark'}, {'name': 'sklearn'}, {'name': 'catboost'}, {'name': 'CV'}], 'accept_handicapped': False, 'accept_kids': False, 'archived': False, 'response_url': None, 'specializations': [], 'professional_roles': [{'id': '165', 'name': 'Дата-сайентист'}], 'code': None, 'hidden': False, 'quick_responses_allowed': False, 'driver_license_types': [], 'accept_incomplete_resumes': False, 'employer': {'id': '6382', 'name': 'Медиалогия', 'url': 'https://api.hh.ru/employers/6382', 'alternate_url': 'https://hh.ru/employer/6382', 'logo_urls': {'original': 'https://img.hhcdn.ru/employer-logo-original/867798.png', '90': 'https://img.hhcdn.ru/employer-logo/3912067.png', '240': 'https://img.hhcdn.ru/employer-logo/3912068.png'}, 'vacancies_url': 'https://api.hh.ru/vacancies?employer_id=6382', 'accredited_it_employer': False, 'trusted': True}, 'published_at': '2024-05-02T17:45:01+0300', 'created_at': '2024-05-02T17:45:01+0300', 'initial_created_at': '2024-05-02T17:45:01+0300', 'negotiations_url': None, 'suitable_resumes_url': None, 'apply_alternate_url': 'https://hh.ru/applicant/vacancy_response?vacancyId=98269481', 'has_test': False, 'test': None, 'alternate_url': 'https://hh.ru/vacancy/98269481', 'working_days': [], 'working_time_intervals': [], 'working_time_modes': [], 'accept_temporary': False, 'languages': [], 'approved': True}
Сложная часть¶
Задача 1.¶
Исследуем профессию Data Scientist. Найдите как можно больше вакансий по этой профессии в Москве. Учтите, что имеет смысл искать также по другим ключевым словам, например, аналитик данных
.
В полученную выборку некоторые вакансии могли попасть несколько раз. Удалите дубликаты.
Загрузите подробное описание каждой вакансии и создайте удобную для дальнейших действий таблицу данных.
Полученную таблицу необходимо сохранить в формате xlsx и отправить боту вместе с решением.
Вопрос 1. Сколько сейчас доступно вакансий по вашему запросу?
Вопрос 2. Какие навыки чаще всего встречаются в вакансиях по данной специальности?
Для этого найдите соответствующее поле в данных из полного описания вакансий, проанализируйте его и составьте список навыков и количество упоминаний каждого. Визуализируйте полученную информацию по топ-15 навыков.
Вопрос 3. Какую зарплату готовы платить работодатели? Соберите некоторым образом статистику и постройте гистограмму.
При работе с данными о заработной плате обратите внимание на валюту и gross/net. Постоянно подгружать курс валюты не требуется, достаточно фиксировать какой-то один более менее актуальный.
Вопрос 4. Какой формат работы предлагается (в офисе / удаленно / ...)?
Проведите аналогичный анализ для наиболее привлекательной для вас профессии в любом регионе. Если это Data Scientist, то для анализа выберите другую. В данном пункте спокойно можно сделать копипасту кода.
Не забывайте про выводы.
Факультативная часть¶
Задача 2.¶
Для одной из рассмотренных ранее профессий исследуйте, в каком районе Москвы данная вакансия пользуется наибольшим и наименьшим спросом. Не забудьте про визуализацию, в частности, постройте распределений вакансий на карте.
Напоминание. Работа в некоторой степени творческая, поэтому конкретные детали решения в основном остаются на усмотрение автора решения.
Какие выводы можно сделать из построенных графиков?
Задача 3.¶
1. Проверьте, во скольких вакансиях среди выгруженных указана зарплата?
На основе описания вакансий с известной зарплатой попробуйте оценить ожидаемую зарплату для всех остальных вакансий. Для этого на основе текстового описания вакансии можно построить эмбеддинги (любые подходящие нейросетевые или просто one-hot кодирование). По этим эмбеддингам обучите некоторую модель предсказывать зарплату.
Не забудьте по общий пайплайн ML-моделей, а также про применимость различных методов.
2. Выполните кластеризацию вакансий, используя построенные эмбеддинги. Визуализируйте результаты и проинтерпретируйте кластеры.
Не забывайте про выводы.