891 KiB
Начало лабораторной¶
Добавление библиотек
# Основные библиотеки
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 файла в датафрейм
df = pd.read_csv(".//static//csv//ds_salaries.csv")
print(df.columns)
Посмотрим краткое содержание датасета. Видим, что датасет состоит из 3755 строк и 11 столбцов
df.info()
df.head()
df.describe()
Бизнес-цель 1: Определить факторы, влияющие на уровень зарплаты сотрудников. Построение модели для выявления и анализа факторов, которые наиболее сильно влияют на размер зарплаты.
Бизнес-цель 2: Прогнозирование уровня зарплаты сотрудников в зависимости от должности и опыта. Разработка модели, которая может прогнозировать зарплату на основе различных входных признаков.
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())
Разделение данных на обучающую, контрольную и тестовую выборки
# Разбиение на обучающую и тестовую выборки (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]}')
Оценка сбалансированности выборок для каждого набора данных
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()
Конструирование признаков
# Дискретизация '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())
Применение Featuretools для синтеза признаков
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())
Оценка качества признаков (обучение модели и предсказания)
# Создание модели с дополнительными гиперпараметрами
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 (MAE) равно 0.48, что указывает на то, что модель в среднем предсказывает зарплаты с ошибкой около 48% от истинных значений. Это может быть вполне приемлемым результатом в зависимости от сложности задачи и данных.
Время обучения меньше 1 секунды - это хороший результат.
Mean CV score: 0.45 показывает, насколько хорошо модель работает на разных поднаборах данных. Чем выше это значение, тем стабильнее модель. В данном случае свидетельствует о средней стабильности модели.