Лабораторная работа №6: Комплексный EDA и Feature Engineering
Цель: Научиться не просто "смотреть" на данные, а готовить их для моделей машинного обучения. Мы проведем очистку от выбросов, создадим новые сильные признаки (Feature Engineering) и преобразуем категориальные переменные в цифры.
Инструменты:
- Python 3, Pandas, NumPy
- Seaborn, Matplotlib
- Датасет: Medical Cost Personal Datasets (Затраты на страховку).
Описание данных:
Мы будем предсказывать charges (медицинские расходы).
Признаки: age, sex, bmi (индекс массы тела), children, smoker, region.
Часть 1: Анализ и обработка выбросов (Outliers)
Выбросы могут исказить работу моделей (особенно линейных). Наша цель — найти их и аккуратно обработать.
Задание 1.1:
- Загрузите датасет.
- Постройте Boxplot для колонки
bmi. Видите точки за "усами"? Это выбросы. - Постройте гистограмму распределения
bmi.
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np
url = "[https://raw.githubusercontent.com/stedy/Machine-Learning-with-R-datasets/master/insurance.csv](https://raw.githubusercontent.com/stedy/Machine-Learning-with-R-datasets/master/insurance.csv)"
df = pd.read_csv(url)
# TODO: Постройте boxplot для 'bmi'
# plt.figure(figsize=(8, 4))
# sns.boxplot(...)
# plt.title("BMI Boxplot")
# plt.show()
# TODO: Постройте гистограмму (histplot/distplot) для 'bmi'
# ...Часть 2: Feature Engineering (Создание признаков)
Модели любят признаки, которые несут прямой физический смысл.
Задание 2.1: Категоризация (Binning)
Возраст — непрерывная величина. Иногда полезно разбить её на группы.
Создайте колонку age_group на основе age:
- 18-35: 'Young'
- 36-55: 'Middle'
- 56+: 'Senior'
Используйте pd.cut.
# TODO: Создайте bins и labels
# bins = [17, 35, 55, 100]
# labels = ['Young', 'Middle', 'Senior']
# TODO: Примените pd.cut
# df['age_group'] = pd.cut(..., bins=bins, labels=labels)
# print(df['age_group'].value_counts())Задание 2.2: Interaction Features (Взаимодействие)
В медицине известно: курение вредно. Но курение при ожирении (BMI > 30) — это смертельное комбо, которое резко повышает расходы.
Создайте признак obese_smoker (Ожирение + Курильщик):
- Равен 1, если
bmi> 30 Иsmoker== 'yes'. - Равен 0 в остальных случаях.
# TODO: Создайте бинарный признак (можно использовать astype(int))
# df['obese_smoker'] = ...
# Проверим, как этот признак влияет на среднюю стоимость
# print(df.groupby('obese_smoker')['charges'].mean())Часть 3: Трансформация целевой переменной
Посмотрите на распределение расходов (charges).
Проблема скошенных данных
Целевые переменные, связанные с деньгами, часто имеют длинный "хвост" вправо. Линейные модели с трудом предсказывают такие распределения, поэтому их нужно приводить к нормальному виду.
Задание 3.1: Log Transformation
- Постройте гистограмму
charges. Вы увидите длинный "хвост" справа (Right Skewed). Модели такое не любят. - Создайте колонку
log_charges, применив натуральный логарифм:np.log1p(log(x+1)). - Постройте гистограмму новой колонки. Она должна стать похожей на колокол.
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
# Исходное распределение
sns.histplot(df['charges'], ax=axes[0], kde=True)
axes[0].set_title('Original Charges')
# TODO: Примените логарифмирование
# df['log_charges'] = np.log1p(...)
# Логарифмированное распределение
# sns.histplot(df['log_charges'], ax=axes[1], kde=True)
# axes[1].set_title('Log Transformed Charges')
plt.show()Часть 4: Кодирование (Encoding) и Корреляция
Чтобы увидеть полную картину, нужно превратить текст в цифры.
Задание 4.1: One-Hot Encoding
Преобразуйте категориальные переменные (sex, smoker, region, age_group) в числовой формат (One-Hot), используя pd.get_dummies.
- Аргумент
drop_first=Trueудаляет дублирующие столбцы (чтобы избежать мультиколлинеарности).
# Выбираем колонки для кодирования
categorical_cols = ['sex', 'smoker', 'region', 'age_group']
# TODO: Примените get_dummies
# df_encoded = pd.get_dummies(df, columns=categorical_cols, drop_first=True)
# print(df_encoded.head())Задание 4.2: Финальная тепловая карта
Постройте Heatmap корреляций для df_encoded.
Найдите топ-3 признака, которые сильнее всего коррелируют с charges.
plt.figure(figsize=(12, 10))
# TODO: Постройте heatmap для df_encoded
# corr = df_encoded.corr()
# sns.heatmap(corr, annot=True, fmt=".2f", cmap='coolwarm')
plt.show()
# Какой признак имеет самую высокую корреляцию с charges?
# Ответ напишите в комментарии.