Ведите переговоры о зарплате как профессионал: Оценщик зарплаты на основе описания вакансии с помощью глубокой нейронной сети

ИИ и нейросети в финансах

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

  1. Цели
    После завершения этой лабораторной работы вы будете обладать следующими навыками:
  • Очищать и нормализовать текст, а затем преобразовывать его в числовые векторы с помощью вкраплений слов.
  • Создавать обучающие и тестовые наборы из предварительно обработанных данных.
  • Создавать и обучать модель глубокой нейронной сети с помощью фреймворков.
  • Оцените работу модели на тестовых данных.
  • Развернуть обученную модель для дальнейшего использования на новых данных.
  1. Установка
    Установка и загрузка необходимых библиотек
pip install -U 'yellowbrick' 'skillsnetwork' 'sentence-transformers' 'seaborn' 
import skillsnetwork
await skillsnetwork.download_dataset("https://cf-courses-data.s3.us.cloud-object-storage.appdomain.cloud/IBMSkillsNetwork-GPXX086PEN/data/df1_datascience_jobs.csv")
await skillsnetwork.download_dataset("https://cf-courses-data.s3.us.cloud-object-storage.appdomain.cloud/IBMSkillsNetwork-GPXX086PEN/data/df2_datascience_jobs.csv")

import re
from tqdm import tqdm
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
  1. Наборы данных
    Мы нашли три набора данных, в которых собраны вакансии специалистов по анализу данных из разных источников в Интернете.

Первая база данных, используемая в данном проекте, получена из Data World и содержит 10 000 объявлений о вакансиях для специалистов по анализу данных [ссылка]. Информация о зарплате сохранена, а записи без информации о зарплате удалены. Второй набор данных собран Люком Барусом и доступен на Kaggle [ссылка]. Вы также можете скачать эти два набора данных по ссылкам: df1 и df2.

3.1. Проектирование набора данных
После загрузки этих трех наборов данных нам необходимо создать инклюзивный набор данных, который содержит следующую информацию:

Заголовок: строка ➜ Название вакансии
Имя_компании: string ➜ Название компании
City: string ➜ Название города, в котором размещена вакансия
State: string ➜ Название штата, в котором предлагается работа
Description: string ➜ Описание вакансии
Зарплата: число ➜ Предлагаемая или предполагаемая зарплата в год

# Load the datasets and having a quick look
df1 = pd.read_csv('df1_datascience_jobs.csv') # data from DataWorld
df2 = pd.read_csv('df2_datascience_jobs.csv') # data from Kaggle
Быстрый взгляд на первый набор данных

Как видите, набор данных содержит множество столбцов, и мы выберем только те, которые имеют отношение к нашему анализу.

# select the columns we are interested
df1 = df1[['job_title','company_name','state','job_description','salary_offered']]

# romove the rows without salaries
df1 = df1[df1['salary_offered'].notna()]
df1.info()
# funtion for cleaning the salary column
def salary_extract(salaries):
    for i in range(len(salaries)):
        # replace k or K with 000
        salaries[i] = re.sub("[kK]", "000", salaries[i])
        
        # Use a regular expression to extract the numbers
        salaries[i] = re.findall(r'\d+', salaries[i])

        # Convert the numbers from strings to integers
        numbers = [int(x) for x in salaries[i]]

        # Calculate the mean of the numbers
        salaries[i] = sum(numbers) / len(numbers)
        
    return salaries
# clean the salary offered

salaries = df1.salary_offered.tolist()
salaries = salary_extract(salaries)

df1['salary_offered'] = salaries

# renaming the columns for consistency
df1.rename(columns={"job_title": "Title","company_name":"Company","state":"Location","job_description":"Description","salary_offered":"Salary"}, inplace=True)
df1.head()

Первый набор данных (df1) готов. давайте очистим второй набор данных (df2).

 df2.columns
# select the columns and remove the unwanted records with no description
df2= df2[['title','company_name','location','description','salary_standardized']]
df2 = df2[df2['salary_standardized'].notna()]
df2.head(2)

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

Следующий код выполняет итерации по каждой строке в списке строк. Он проверяет, содержит ли строка запятую, используя оператор in для каждой строки. Если да, то используется метод str.split() для разделения строки на запятые и берется последний элемент полученного списка, который должен быть состоянием. Он удаляет любые пробелы после state с помощью метода str.strip(), а затем добавляет state в список state. Если в строке нет запятой, то к списку штатов добавляется United States. Наконец, выводится содержимое списка штатов.

locations = df2.location.tolist()

# looping through the locations and extracting state if exists
states = [string.split(",")[-1].strip() if "," in string else "United States" for string in locations ]
df2['location'] = states

# rename the column for consitency
df2.rename(columns={"title": "Title","company_name":"Company","location":"Location","description":"Description","salary_standardized":"Salary"}, inplace=True)
df2.info()

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

3.2 Подготовка основного набора данных
Наши три набора данных готовы, поэтому мы объединим их по строкам.

# combining the two datasets
data = pd.concat([df1, df2], ignore_index=True, sort=False)
data.info()
# so we have 5778 non-null rows

Для обеспечения качества нашего анализа мы будем удалять все объявления о вакансиях с недостаточным описанием компании. Так, мы удаляем те описания, в которых менее 250 символов.

# get the list of job description lenth, and print those less than 250 characters
desc_len = [len(x) for x in data.Description]
print('number of jobs with short descriptions ==>',sum(i < 250 for i in desc_len))

# finding short job descriptions (less than 250 characters) and removind them
ind = [i for i, x in enumerate(desc_len) if x < 250]
data = data.drop(data.index[ind], axis=0)
data.shape
# seems we have faulty data at some point
data.sort_values(by=['Salary'],ascending=False)
# removing those dataset with extreme high or low values in Salary
data = data.query('Salary >= 40000 and Salary<=250000')

4. Изучение набора данных

data['Salary'].describe()
# lets plot the salary
sns.boxplot(y = 'Salary', data = data)
# Plotting the distribution of the salaries.

# make the xlabel ticks smaller to fit properly
plt.rcParams['xtick.labelsize'] = 8
# plot histogram for observing the distribution
data['Salary'].plot.hist(bins=30, alpha=0.5)

Составление списка самых высокооплачиваемых компаний:

# grouping by companies and calculating the mean salaries
top_companies = data.groupby(['Company']).mean().sort_values('Salary',ascending=False).head(20)

plt.style.use('seaborn-darkgrid') 
top_companies.plot(kind='barh',legend=False,color='olive')
plt.xlabel('Salary')
plt.ylabel('Companies')
plt.title('Top 25 Paying Companies')

Составление списка самых высокооплачиваемых должностей специалистов по анализу данных:

# grouping by title and calculating the mean salaries
top_title = data.groupby(['Title']).mean().sort_values('Salary',ascending=False).head(20)

plt.style.use('seaborn-darkgrid') 
top_title.plot(kind='barh',legend=False,color='olive')
plt.xlabel('Salary')
plt.ylabel('Titles')
plt.title('Top 25 Paying Data Scientist Titles')
plt.show()
  1. Преобразование текста для ML-модели
    Мы выбираем столбец Описание и обрабатываем его в векторы. Шаги для обработки текста следующие:
  1. Преобразование всего текста в нижний регистр для согласованности и простоты обработки.
  2. Исключить все знаки препинания и стоп-слова, так как они не вносят вклад в смысл текста.
  3. Используйте стебли для сокращения слов до их базовой формы для лучшей группировки похожих слов.
  4. Применить лемматизацию для дальнейшей нормализации слов, рассматривая вариации слова как одно и то же.
  5. Преобразование обработанного текста в числовые векторы с помощью модели S-BERT для математического анализа и обработки.
text = data['Description']
import string
import re
from nltk.corpus import stopwords
import nltk
# stemming using PorterStemmer
from nltk.stem import PorterStemmer

from nltk.stem import WordNetLemmatizer

# for lemmatization, you need to download "wordnet" repository which contains family of words
nltk.download("wordnet")

# function for text preparation
def text_prep(text):
    # make it lower case
    text = [t.lower() for t in text]
    text[:3]

    # Strip all punctuation from each article
    # This uses str.translate to map all punctuation to the empty string
    table = str.maketrans('', '', string.punctuation)
    text = [t.translate(table) for t in text]

    # Convert all numbers in the article to the word 'num' using regular expressions
    text = [re.sub(r'\d+', 'num', t) for t in text]
    # remove '\n' from the text 
    text = [t.replace('\n',' ') for t in text]

    # Use the re.sub() function to replace all characters that are not alphanumeric, period, underscore, hyphen, or space
    text = [re.sub(r'[^a-zA-Z0-9._\s]', '', t) for t in text]
    # remove double spaces
    text = [re.sub(r'\s+', ' ', t) for t in text]

    # creating stemmer model and fit evey sentence to it
    stemmer = PorterStemmer()
    text = [stemmer.stem(t) for t in text]

    # create lemmatizer and apply it for every sentence in the text
    lem = nltk.stem.wordnet.WordNetLemmatizer()
    text = [lem.lemmatize(t) for t in text]
    return text
text = text_prep(text)
# print a sample of the text
text[3]

SentenceTransformer(‘all-MiniLM-L6-v2’) — это предварительно обученная модель, предоставляемая библиотекой SentenceTransformers, которая используется для генерации вкраплений предложений. Она основана на MiniLM, версии RoBERT — языковой модели, отточенной на различных задачах понимания естественного языка. Версия ‘all-MiniLM-L6-v2’ обучена на всех доступных данных, имеет 6 слоев. Эти вкрапления могут быть использованы в качестве входных данных для других моделей машинного обучения для таких задач, как классификация текстов, генерация текстов и ответы на вопросы.

from sentence_transformers import SentenceTransformer
from sentence_transformers import util
model_Sen = SentenceTransformer('all-MiniLM-L6-v2')

Модели SentenceTransformer основаны на сложных архитектурах трансформаторов, которые, как известно, являются большими и глубокими нейронными сетями. Генерация вкраплений из этих моделей может быть вычислительно дорогой и может занять больше времени по сравнению с более простыми моделями. Это связано с тем, что генерация вкраплений требует значительного количества вычислительных ресурсов, таких как мощность CPU или GPU. Поэтому обратите внимание, что запуск следующих ячеек может занять несколько минут.

# this method encode the sentences into numpy vectors which can be used for clustering task
# by increasing the batch size, the coversion time can be reduced
# the vectorization may take time

embeddings = model_Sen.encode(text, convert_to_numpy = True, show_progress_bar=True,batch_size=100) # By default, convert_to_numpy = True
embeddings.shape

Процесс трансформации

# Splitting the data for training and testing

from sklearn.model_selection import train_test_split

# Split the data into independent and dependent variables
X = pd.DataFrame(embeddings)
y = data['Salary']

# Split the data into train and test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=11)

# print the shape of train and test data
print("X_train shape: ", X_train.shape)
print("y_train shape: ", y_train.shape)
print("X_test shape: ", X_test.shape)
print("y_test shape: ", y_test.shape)

В этом проекте мы используем модель глубокой нейронной сети (DNN) для обучения и тестирования. Глубокая нейронная сеть — это тип искусственной нейронной сети с несколькими скрытыми слоями между входным и выходным слоями. Она называется «глубокой» из-за количества скрытых слоев.

При реализации модели DNN мы используем библиотеку Keras, которая является высокоуровневой библиотекой глубокого обучения для Python, предоставляющей удобный способ определения и обучения DNN. Она имеет удобный API, который позволяет разработчикам быстро и легко создавать и экспериментировать с различными архитектурами DNN. Библиотека поддерживает множество бэкендов, таких как TensorFlow. В Keras вы можете определить структуру вашей DNN с помощью встроенных слоев и функций активации, затем «скомпилировать» модель и «подогнать» ее под ваши данные для обучения.

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

Метод Dropout работает путем случайной установки части входов на ноль во время каждого шага обучения, эффективно «исключая» эти входы из вычислений. Это заставляет модель изучать несколько независимых представлений одних и тех же данных и уменьшает зависимость от какой-либо одной характеристики, делая модель более надежной и обобщаемой. В Keras слой Dropout можно добавить в модель, просто вставив его между другими слоями.

from keras.layers import Dense, Dropout
from keras.models import Sequential
from keras.optimizers import Adam
from sklearn.metrics import mean_absolute_error

# Create a DNN model
model = Sequential()

# The Input Layer
model.add(Dense(512, kernel_initializer='normal',input_dim = X_train.shape[1], activation='relu'))

# The Hidden Layers (Dropout layers for avoiding overfitting)
model.add(Dropout(0.2))
model.add(Dense(512, kernel_initializer='normal',activation='relu'))
model.add(Dropout(0.3))
model.add(Dense(512, kernel_initializer='normal',activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(256, kernel_initializer='normal',activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(128, kernel_initializer='normal',activation='relu'))

# The Output Layer
model.add(Dense(1, kernel_initializer='normal',activation='selu'))

# Compile the network
model.compile(loss='mean_absolute_error', optimizer='adam', metrics=['mean_absolute_error'])
model.summary()

Выполнение модели:

model.fit(X_train, y_train, epochs=40, batch_size=35, validation_split = 0.2)

Тестирование модели:

# Make predictions on the test data
y_pred = model.predict(X_test)

# Calculate the mean absolute error of the model
mae = mean_absolute_error(y_test, y_pred)
print("Mean Absolute Error: ", mae)

Средняя абсолютная ошибка в 18 000 $ является неплохой, учитывая разновидности зарплатной политики в разных компаниях и силу индивидуальных переговоров.

6. Оценка новой вакансии (развертывание модели)

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

sample_job_description=""" 
Job description Company Description 
We help the world see new possibilities and inspire change for better tomorrows. Our analytic solutions bridge content, data, and analytics to help business, people, and society become stronger, more resilient, and sustainableJob Description
• Under supervision, participates in the development and execution of analysis project plans for timely project completion. May contribute to project hypothesis and goal setting.
• Utilizes statistical and machine learning techniques to create high-performing models that comply with regulatory and privacy requirements and address business objectives and client needs.
• Ensures statistical, computational, and algorithmic validity of results.
• Performs analyses of structured and unstructured data to solve multiple and complex business problems, utilizing advanced statistical, mathematical and machine learning technique.
• Ability to keep up to date with emerging methods and environments.
• Provides required support for project delivery and implementation.
• Collaboration with Verisk Cloud Data Lakehouse to support Insurance Analytics work
• Develop, construct, test, and maintain architectures
• Align architecture with business requirements
• Data acquisition
• Develop data set processes
• Use programming language and tools
• Identify ways to improve data reliability, efficiency, and quality
• Deploy sophisticated analytics programs, machine learning, and statistical methods
• Creates clear and easy to understand documents for product support (technical).
• Presents analysis ideas, progress reports and results to internal managers, project managers.
• Collaborates with Lead or Principal Data Scientist to develop technical/business approaches and new or enhanced technical tools.

LI-SM1

Qualifications

Required:
• Graduate-level degree with concentration in a quantitative discipline such as statistics, mathematics, economics, operations research, computer science or aligned discipline.
• Skilled with feature engineering, model selection and assessment methodologies, and familiarity with all stages of the data science pipeline.
• Skilled programming in – SQL, Python, PySpark,
• Knowledge in and applied experience with statistical and machine learning.
• Applied, practical experience using statistical and machine learning computer languages (e.g. R, Python, SLQ).
• Working familiarity with cloud computing environments.
• Demonstrated skills with Data Engineering Tools – Database, Data Transformation, Data Ingestion, Data Mining, Data Warehousing and ETL/LTE, Reasl-time Processing Framework, Data Buffering, Cloud Computing, and Data Visualization
• Logical, evidence-based problem solving and critical thinking skills.

Preferred:
• Insurance experience, focusing on the personal lines or related business content.

Additional Information

At the heart of what we do is help clients manage risk. Verisk (Nasdaq: VRSK) provides data and insights to our customers in insurance, energy and the financial services markets so they can make faster and more informed decisions. 

Our global team uses AI, machine learning, automation, and other emerging technologies to collect and analyze billions of records. We provide advanced decision-support to prevent credit, lending, and cyber risks. In addition, we monitor and advise companies on complex global matters such as climate change, catastrophes, and geopolitical issues.

But why we do our work is what sets us apart. It stems from a commitment to making the world better, safer and stronger.

It’s the reason Verisk is part of the UN Global Compact sustainability initiative. It’s why we made a commitment to balancing 100 percent of our carbon emissions. It’s the aim of our “returnship” program for experienced professionals rejoining the workforce after time away. And, its what drives our annual Innovation Day, where we identify our next first-to-market innovations to solve our customers’ problems. 

At its core, Verisk uses data to minimize risk and maximize value. But far bigger, is why we do what we do.

At Verisk you can build an exciting career with meaningful work; create positive and lasting impact on business; and find the support, coaching, and training you need to advance your career. We have received the Great Place to Work® Certification for the 7th consecutive year. Weve been recognized by Forbes as a World’s Best Employer and a Best Employer for Women, testaments to our culture of engagement and the value we place on an inclusive and diverse workforce. Verisk’s Statement on Racial Equity and Diversity supports our commitment to these values and affecting positive and lasting change in the communities where we live and work.

Verisk Analytics is an equal opportunity employer.

All members of the Verisk Analytics family of companies are equal opportunity employers. We consider all qualified applicants for employment without regard to race, religion, color, national origin, citizenship, sex, gender identity and/or expression, sexual orientation, veterans status, age or disability.

"""

Получите зарплату:

# Prepare your text through text prepration and vectorization
your_text = text_prep([sample_job_description])
your_text_embeddings = model_Sen.encode(your_text, convert_to_numpy = True) 

# Estimate the salary based on the model we trained before
estimatation = model.predict(your_text_embeddings)

print("Estimated salary for the job ==> ", int(estimatation[0]), "U$D")

Спасибо, что читаете!

Дисклеймер: Материалы сайта cb-dc.ru носят исключительно информационный характер и не являются финансовым советом, инвестиционной рекомендацией или призывом к совершению каких-либо финансовых операций. Перед принятием инвестиционных решений проконсультируйтесь с квалифицированным финансовым советником. Инвестиции в криптовалюты и цифровые активы сопряжены с высоким уровнем риска.
Оцените статью
CBDC
Добавить комментарий