Files

891 KiB
Raw Permalink Blame History

Начало лабораторной

Добавление библиотек

In [18]:
# Основные библиотеки
import pandas as pd

# Визуализация
import matplotlib.pyplot as plt
import seaborn as sns

# Машинное обучение
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_absolute_error

# Для работы с фреймворком Featuretools
import featuretools as ft

Выгрузка данных из csv файла в датафрейм

In [19]:
df = pd.read_csv(".//static//csv//ds_salaries.csv")
print(df.columns)
Index(['work_year', 'experience_level', 'employment_type', 'job_title',
       'salary', 'salary_currency', 'salary_in_usd', 'employee_residence',
       'remote_ratio', 'company_location', 'company_size'],
      dtype='object')

Посмотрим краткое содержание датасета. Видим, что датасет состоит из 3755 строк и 11 столбцов

In [20]:
df.info()
df.head()
df.describe()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 3755 entries, 0 to 3754
Data columns (total 11 columns):
 #   Column              Non-Null Count  Dtype 
---  ------              --------------  ----- 
 0   work_year           3755 non-null   int64 
 1   experience_level    3755 non-null   object
 2   employment_type     3755 non-null   object
 3   job_title           3755 non-null   object
 4   salary              3755 non-null   int64 
 5   salary_currency     3755 non-null   object
 6   salary_in_usd       3755 non-null   int64 
 7   employee_residence  3755 non-null   object
 8   remote_ratio        3755 non-null   int64 
 9   company_location    3755 non-null   object
 10  company_size        3755 non-null   object
dtypes: int64(4), object(7)
memory usage: 322.8+ KB
Out[20]:
<style scoped=""> .dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } </style>
work_year salary salary_in_usd remote_ratio
count 3755.000000 3.755000e+03 3755.000000 3755.000000
mean 2022.373635 1.906956e+05 137570.389880 46.271638
std 0.691448 6.716765e+05 63055.625278 48.589050
min 2020.000000 6.000000e+03 5132.000000 0.000000
25% 2022.000000 1.000000e+05 95000.000000 0.000000
50% 2022.000000 1.380000e+05 135000.000000 0.000000
75% 2023.000000 1.800000e+05 175000.000000 100.000000
max 2023.000000 3.040000e+07 450000.000000 100.000000

Бизнес-цель 1: Определить факторы, влияющие на уровень зарплаты сотрудников. Построение модели для выявления и анализа факторов, которые наиболее сильно влияют на размер зарплаты.

Бизнес-цель 2: Прогнозирование уровня зарплаты сотрудников в зависимости от должности и опыта. Разработка модели, которая может прогнозировать зарплату на основе различных входных признаков.

In [21]:
print(df.isnull().sum())
df = df.dropna()

df = pd.get_dummies(df, drop_first=True)

Q1 = df['salary_in_usd'].quantile(0.25)
Q3 = df['salary_in_usd'].quantile(0.75)
IQR = Q3 - Q1

# Определяем границы выбросов
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR

# Фильтруем выбросы
df = df[(df['salary_in_usd'] >= lower_bound) & (df['salary_in_usd'] <= upper_bound)]

# Масштабирование числовых признаков
scaler = StandardScaler()
df[['salary_in_usd', 'work_year']] = scaler.fit_transform(df[['salary_in_usd', 'work_year']])

print(df.head())
work_year             0
experience_level      0
employment_type       0
job_title             0
salary                0
salary_currency       0
salary_in_usd         0
employee_residence    0
remote_ratio          0
company_location      0
company_size          0
dtype: int64
   work_year  salary  salary_in_usd  remote_ratio  experience_level_EX  \
0   0.910664   80000      -0.834983           100                False   
1   0.910664   30000      -1.798120           100                False   
2   0.910664   25500      -1.875727           100                False   
3   0.910664  175000       0.702551           100                False   
4   0.910664  120000      -0.245980           100                False   

   experience_level_MI  experience_level_SE  employment_type_FL  \
0                False                 True               False   
1                 True                False               False   
2                 True                False               False   
3                False                 True               False   
4                False                 True               False   

   employment_type_FT  employment_type_PT  ...  company_location_SG  \
0                True               False  ...                False   
1               False               False  ...                False   
2               False               False  ...                False   
3                True               False  ...                False   
4                True               False  ...                False   

   company_location_SI  company_location_SK  company_location_TH  \
0                False                False                False   
1                False                False                False   
2                False                False                False   
3                False                False                False   
4                False                False                False   

   company_location_TR  company_location_UA  company_location_US  \
0                False                False                False   
1                False                False                 True   
2                False                False                 True   
3                False                False                False   
4                False                False                False   

   company_location_VN  company_size_M  company_size_S  
0                False           False           False  
1                False           False            True  
2                False           False            True  
3                False            True           False  
4                False            True           False  

[5 rows x 271 columns]

Разделение данных на обучающую, контрольную и тестовую выборки

In [22]:
# Разбиение на обучающую и тестовую выборки (80%/20%)
X = df.drop('salary_in_usd', axis=1)  # Все столбцы, кроме целевой переменной
y = df['salary_in_usd']  # Целевая переменная

# Сначала делаем разбиение на обучающую и тестовую выборки
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# Разбиение обучающей выборки на обучение и валидацию (80% для обучения, 20% для валидации)
X_train, X_val, y_train, y_val = train_test_split(X_train, y_train, test_size=0.2, random_state=42)

# Проверяем размеры выборок
print(f'Размер обучающей выборки: {X_train.shape[0]}')
print(f'Размер валидационной выборки: {X_val.shape[0]}')
print(f'Размер тестовой выборки: {X_test.shape[0]}')
Размер обучающей выборки: 2362
Размер валидационной выборки: 591
Размер тестовой выборки: 739

Оценка сбалансированности выборок для каждого набора данных

In [23]:
plt.figure(figsize=(12, 6))

# Гистограммы для всех выборок
plt.hist(y_train, bins=30, alpha=0.5, label='Обучающая выборка', color='skyblue', edgecolor='black')
plt.hist(y_val, bins=30, alpha=0.5, label='Валидационная выборка', color='orange', edgecolor='black')
plt.hist(y_test, bins=30, alpha=0.5, label='Тестовая выборка', color='green', edgecolor='black')

plt.title('Распределение зарплаты для всех выборок')
plt.xlabel('Зарплата')
plt.ylabel('Частота')
plt.legend(loc='upper right')
plt.show()
No description has been provided for this image

Конструирование признаков

In [24]:
# Дискретизация 'salary_in_usd'
df['salary_category'] = pd.cut(df['salary_in_usd'], bins=[-1, 30000, 70000, 150000, 300000], labels=["Low", "Medium", "High", "Very High"])

# Дискретизация 'work_year' - количество лет опыта
df['work_year_category'] = pd.cut(df['work_year'], bins=[0, 2, 5, 10, 20], labels=["Beginner", "Intermediate", "Experienced", "Expert"])

print(df.columns)

df['is_large_company'] = df['company_size_M'].apply(lambda x: 1 if x == '1' else 0)

print(df.head())

# Выводим несколько строк датафрейма, чтобы проверить изменения
print(df[['work_year', 'work_year_category', 'salary_in_usd', 'salary_category', 'is_large_company']].head())

# Статистика для числовых признаков
print(df[['salary_in_usd', 'work_year']].describe())

# Частотное распределение категориальных признаков
print(df['salary_category'].value_counts())
print(df['work_year_category'].value_counts())
print(df['is_large_company'].value_counts())
Index(['work_year', 'salary', 'salary_in_usd', 'remote_ratio',
       'experience_level_EX', 'experience_level_MI', 'experience_level_SE',
       'employment_type_FL', 'employment_type_FT', 'employment_type_PT',
       ...
       'company_location_SK', 'company_location_TH', 'company_location_TR',
       'company_location_UA', 'company_location_US', 'company_location_VN',
       'company_size_M', 'company_size_S', 'salary_category',
       'work_year_category'],
      dtype='object', length=273)
   work_year  salary  salary_in_usd  remote_ratio  experience_level_EX  \
0   0.910664   80000      -0.834983           100                False   
1   0.910664   30000      -1.798120           100                False   
2   0.910664   25500      -1.875727           100                False   
3   0.910664  175000       0.702551           100                False   
4   0.910664  120000      -0.245980           100                False   

   experience_level_MI  experience_level_SE  employment_type_FL  \
0                False                 True               False   
1                 True                False               False   
2                 True                False               False   
3                False                 True               False   
4                False                 True               False   

   employment_type_FT  employment_type_PT  ...  company_location_TH  \
0                True               False  ...                False   
1               False               False  ...                False   
2               False               False  ...                False   
3                True               False  ...                False   
4                True               False  ...                False   

   company_location_TR  company_location_UA  company_location_US  \
0                False                False                False   
1                False                False                 True   
2                False                False                 True   
3                False                False                False   
4                False                False                False   

   company_location_VN  company_size_M  company_size_S  salary_category  \
0                False           False           False              Low   
1                False           False            True              NaN   
2                False           False            True              NaN   
3                False            True           False              Low   
4                False            True           False              Low   

   work_year_category  is_large_company  
0            Beginner                 0  
1            Beginner                 0  
2            Beginner                 0  
3            Beginner                 0  
4            Beginner                 0  

[5 rows x 274 columns]
   work_year work_year_category  salary_in_usd salary_category  \
0   0.910664           Beginner      -0.834983             Low   
1   0.910664           Beginner      -1.798120             NaN   
2   0.910664           Beginner      -1.875727             NaN   
3   0.910664           Beginner       0.702551             Low   
4   0.910664           Beginner      -0.245980             Low   

   is_large_company  
0                 0  
1                 0  
2                 0  
3                 0  
4                 0  
       salary_in_usd     work_year
count   3.692000e+03  3.692000e+03
mean   -2.309456e-16  9.681241e-14
std     1.000135e+00  1.000135e+00
min    -2.226994e+00 -3.438845e+00
25%    -6.785742e-01 -5.391725e-01
50%    -5.984257e-03 -5.391725e-01
75%     6.939277e-01  9.106636e-01
max     2.737579e+00  9.106636e-01
salary_category
Low          3050
Medium          0
High            0
Very High       0
Name: count, dtype: int64
work_year_category
Beginner        1747
Intermediate       0
Experienced        0
Expert             0
Name: count, dtype: int64
is_large_company
0    3692
Name: count, dtype: int64

Применение Featuretools для синтеза признаков

In [25]:
print(df.isnull().sum())
df['salary_category'] = df['salary_category'].fillna(df['salary_category'].mode()[0])
df['work_year_category'] = df['work_year_category'].fillna(df['work_year_category'].mode()[0])
print(df.isnull().sum())

df['index'] = df.index

# Создание EntitySet
es = ft.EntitySet(id="salary_data")

# Добавление данных в EntitySet (с указанием индекса)
es = es.add_dataframe(
    dataframe_name="data_scientists",  # Имя сущности
    dataframe=df,                      # Датафрейм
    index="index",                     # Уникальный идентификатор
    time_index="work_year"             # Если у тебя есть временная метка, используем её
)

# Синтез признаков
features, feature_names = ft.dfs(
    entityset=es, 
    target_dataframe_name="data_scientists", 
    max_depth=1
)

# Просмотр первых сгенерированных признаков
print(features.head())
work_year                 0
salary                    0
salary_in_usd             0
remote_ratio              0
experience_level_EX       0
                       ... 
company_size_M            0
company_size_S            0
salary_category         642
work_year_category     1945
is_large_company          0
Length: 274, dtype: int64
work_year              0
salary                 0
salary_in_usd          0
remote_ratio           0
experience_level_EX    0
                      ..
company_size_M         0
company_size_S         0
salary_category        0
work_year_category     0
is_large_company       0
Length: 274, dtype: int64
       work_year   salary  salary_in_usd  remote_ratio  experience_level_EX  \
index                                                                         
183    -3.438845    15000      -2.056810             0                 True   
2118   -3.438845    95000      -0.677130             0                False   
3119   -3.438845  1000000      -2.082800           100                False   
3120   -3.438845  1000000      -2.082800           100                False   
3138   -3.438845    20000      -1.922136           100                False   

       experience_level_MI  experience_level_SE  employment_type_FL  \
index                                                                 
183                  False                False               False   
2118                  True                False               False   
3119                 False                False               False   
3120                 False                False               False   
3138                 False                False               False   

       employment_type_FT  employment_type_PT  ...  company_location_TH  \
index                                          ...                        
183                  True               False  ...                False   
2118                 True               False  ...                False   
3119                 True               False  ...                False   
3120                 True               False  ...                False   
3138                 True               False  ...                False   

       company_location_TR  company_location_UA  company_location_US  \
index                                                                  
183                  False                False                False   
2118                 False                False                 True   
3119                 False                False                False   
3120                 False                False                False   
3138                 False                False                False   

       company_location_VN  company_size_M  company_size_S  salary_category  \
index                                                                         
183                  False            True           False              Low   
2118                 False            True           False              Low   
3119                 False           False           False              Low   
3120                 False           False           False              Low   
3138                 False            True           False              Low   

       work_year_category  is_large_company  
index                                        
183              Beginner                 0  
2118             Beginner                 0  
3119             Beginner                 0  
3120             Beginner                 0  
3138             Beginner                 0  

[5 rows x 274 columns]

Оценка качества признаков (обучение модели и предсказания)

In [26]:
# Создание модели с дополнительными гиперпараметрами
model = RandomForestRegressor(
    random_state=42,         # Для воспроизводимости
    min_samples_leaf=5,      # Минимальное количество образцов в листьях
    max_features='sqrt'     # Количество признаков для каждого дерева (sqrt - это квадратный корень из количества признаков)
)

# Обучение модели
model.fit(X_train, y_train)

# Предсказания и оценка
y_pred = model.predict(X_val)
mae = mean_absolute_error(y_val, y_pred)
print(f"Mean Absolute Error: {mae}")

import time

# Измерим время обучения модели
start_time = time.time()
model.fit(X_train, y_train)
training_time = time.time() - start_time

# Измерим время предсказания
start_time = time.time()
y_pred = model.predict(X_val)
prediction_time = time.time() - start_time

print(f"Training time: {training_time:.4f} seconds")
print(f"Prediction time: {prediction_time:.4f} seconds")

from sklearn.model_selection import cross_val_score

# Оценка стабильности модели с помощью кросс-валидации
cv_scores = cross_val_score(model, X, y, cv=5, scoring='neg_mean_absolute_error')
print(f"Cross-validation scores: {-cv_scores}")
print(f"Mean CV score: {-cv_scores.mean()}")

# Разделим признаки на несколько групп
numeric_columns = ['work_year', 'salary', 'salary_in_usd', 'remote_ratio']
categorical_columns = ['experience_level_EX', 'experience_level_MI', 'experience_level_SE', 
                       'employment_type_FL', 'employment_type_FT', 'employment_type_PT']
location_columns = ['company_location_US', 'company_location_TH', 'company_location_UA', 'company_location_TR']
company_size_columns = ['company_size_S', 'company_size_M']

# Рассчитываем корреляцию для числовых признаков
numeric_corr = df[numeric_columns].corr()

# Строим график для числовых признаков
plt.figure(figsize=(8, 6))
sns.heatmap(numeric_corr, annot=True, cmap='coolwarm_r', fmt='.2f', vmin=-1, vmax=1)
plt.title("Correlation Matrix - Numeric Features")
plt.show()

# Рассчитываем корреляцию для категориальных признаков (если необходимо, можно применить методы кодирования)
categorical_corr = df[categorical_columns].apply(lambda x: pd.factorize(x)[0]).corr()

# Строим график для категориальных признаков
plt.figure(figsize=(8, 6))
sns.heatmap(categorical_corr, annot=True, cmap='coolwarm_r', fmt='.2f', vmin=-1, vmax=1)
plt.title("Correlation Matrix - Categorical Features")
plt.show()

# Рассчитываем корреляцию для признаков, связанных с местоположением
location_corr = df[location_columns].corr()

# Строим график для местоположений
plt.figure(figsize=(8, 6))
sns.heatmap(location_corr, annot=True, cmap='coolwarm_r', fmt='.2f', vmin=-1, vmax=1)
plt.title("Correlation Matrix - Location Features")
plt.show()

# Рассчитываем корреляцию для всех признаков
corr_matrix = X.corr()
plt.figure(figsize=(16, 12))
sns.heatmap(corr_matrix, annot=True, cmap='coolwarm_r', fmt='.2f', vmin=-1, vmax=1)
plt.title("Correlation Matrix for All Features")
plt.show()
Mean Absolute Error: 0.4835646624323662
Training time: 0.5241 seconds
Prediction time: 0.0600 seconds
Cross-validation scores: [0.48024517 0.47077393 0.38139667 0.42743552 0.49178612]
Mean CV score: 0.45032748163871555
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image

Mean Absolute Error (MAE) равно 0.48, что указывает на то, что модель в среднем предсказывает зарплаты с ошибкой около 48% от истинных значений. Это может быть вполне приемлемым результатом в зависимости от сложности задачи и данных.

Время обучения меньше 1 секунды - это хороший результат.

Mean CV score: 0.45 показывает, насколько хорошо модель работает на разных поднаборах данных. Чем выше это значение, тем стабильнее модель. В данном случае свидетельствует о средней стабильности модели.