ISE_31.Aparyan.mai/lab2.ipynb

396 KiB
Raw Blame History

Лабораторная работа №2

Анализ нескольких датасетов

1.Выбрать три набора данных, которые не соответствуют Вашему варианту задания

2. Провести анализ сведений о каждом наборе данных со страницы загрузки в Kaggle. Какова проблемная область?

Магазины, Цены на автомобиль, Инсульты

Инсульты

Данный датасет используется для предсказания вероятности возникновения инсульта у пациента на основе различных параметров, таких как пол, возраст, наличие заболеваний и статус курения. Инсульт является второй по значимости причиной смерти в мире, по данным Всемирной организации здравоохранения (ВОЗ), и ответственен за около 11% всех случаев смерти.

Информация о колонках

  • id: уникальный идентификатор пациента (int)
  • gender: пол пациента, возможные значения — "Male" (мужчина), "Female" (женщина) или "Other" (другое) (object, строковый)
  • age: возраст пациента (float)
  • hypertension: наличие гипертензии; 0 — если гипертензии нет, 1 — если гипертензия есть (int)
  • heart_disease: наличие сердечных заболеваний; 0 — если заболеваний нет, 1 — если есть (int)
  • ever_married: статус брака; "No" (нет) или "Yes" (да) (object, строковый)
  • work_type: тип работы; возможные значения — "children" (дети), "Govt_job" (государственная работа), "Never_worked" (никогда не работал), "Private" (частный сектор) или "Self-employed" (самозанятый) (object, строковый)
  • Residence_type: тип проживания; "Rural" (сельская местность) или "Urban" (городская местность) (object, строковый)
  • avg_glucose_level: средний уровень глюкозы в крови (float)
  • bmi: индекс массы тела (ИМТ) (float)
  • smoking_status: статус курения; возможные значения — "formerly smoked" (курил раньше), "never smoked" (никогда не курил), "smokes" (курит) или "Unknown" (неизвестно). Значение "Unknown" указывает на недоступность информации о статусе курения пациента (object, строковый)
  • stroke: наличие инсульта; 1 — если инсульт был, 0 — если не был (int)

Каждая строка в датасете содержит соответствующую информацию о пациенте, что позволяет проводить анализ и строить модели для предсказания риска инсульта.

In [61]:
import pandas as pd 

strokes = pd.read_csv("healthcare-dataset-stroke-data.csv")

strokes
Out[61]:
id gender age hypertension heart_disease ever_married work_type Residence_type avg_glucose_level bmi smoking_status stroke
0 9046 Male 67.0 0 1 Yes Private Urban 228.69 36.6 formerly smoked 1
1 51676 Female 61.0 0 0 Yes Self-employed Rural 202.21 NaN never smoked 1
2 31112 Male 80.0 0 1 Yes Private Rural 105.92 32.5 never smoked 1
3 60182 Female 49.0 0 0 Yes Private Urban 171.23 34.4 smokes 1
4 1665 Female 79.0 1 0 Yes Self-employed Rural 174.12 24.0 never smoked 1
... ... ... ... ... ... ... ... ... ... ... ... ...
5105 18234 Female 80.0 1 0 Yes Private Urban 83.75 NaN never smoked 0
5106 44873 Female 81.0 0 0 Yes Self-employed Urban 125.20 40.0 never smoked 0
5107 19723 Female 35.0 0 0 Yes Self-employed Rural 82.99 30.6 never smoked 0
5108 37544 Male 51.0 0 0 Yes Private Rural 166.29 25.6 formerly smoked 0
5109 44679 Female 44.0 0 0 Yes Govt_job Urban 85.28 26.2 Unknown 0

5110 rows × 12 columns

In [62]:
strokes.dtypes
Out[62]:
id                     int64
gender                object
age                  float64
hypertension           int64
heart_disease          int64
ever_married          object
work_type             object
Residence_type        object
avg_glucose_level    float64
bmi                  float64
smoking_status        object
stroke                 int64
dtype: object

Автомобили

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

Информация о колонках

  • ID: уникальный идентификатор автомобиля (int)
  • Price: цена автомобиля (целевой столбец) (int)
  • Levy: налог или сбор, связанный с автомобилем (obect, строковый)
  • Manufacturer: производитель автомобиля (obect, строковый)
  • Model: модель автомобиля (obect, строковый)
  • Prod. year: год производства (int)
  • Category: категория автомобиля (obect, строковый)
  • Leather interior: наличие кожаного салона (да/нет) (obect, строковый)
  • Fuel type: тип топлива (бензин, дизель и т.д.) (obect, строковый)
  • Engine volume: рабочий объем двигателя (obect, строковый)
  • Mileage: пробег автомобиля (obect, строковый)
  • Cylinders: количество цилиндров в двигателе (float)
  • Gear box type: тип коробки передач (механическая, автоматическая и т.д.) (obect, строковый)
  • Drive wheels: тип привода (передний, задний, полный) (obect, строковый)
  • Doors: количество дверей (obect, строковый)
  • Wheel: расположение руля (левосторонний, правосторонний) (obect, строковый)
  • Color: цвет автомобиля (obect, строковый)
  • Airbags: наличие подушек безопасности (int)

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

In [63]:
auto = pd.read_csv("car_price_prediction.csv")

auto
Out[63]:
ID Price Levy Manufacturer Model Prod. year Category Leather interior Fuel type Engine volume Mileage Cylinders Gear box type Drive wheels Doors Wheel Color Airbags
0 45654403 13328 1399 LEXUS RX 450 2010 Jeep Yes Hybrid 3.5 186005 km 6.0 Automatic 4x4 04-May Left wheel Silver 12
1 44731507 16621 1018 CHEVROLET Equinox 2011 Jeep No Petrol 3 192000 km 6.0 Tiptronic 4x4 04-May Left wheel Black 8
2 45774419 8467 - HONDA FIT 2006 Hatchback No Petrol 1.3 200000 km 4.0 Variator Front 04-May Right-hand drive Black 2
3 45769185 3607 862 FORD Escape 2011 Jeep Yes Hybrid 2.5 168966 km 4.0 Automatic 4x4 04-May Left wheel White 0
4 45809263 11726 446 HONDA FIT 2014 Hatchback Yes Petrol 1.3 91901 km 4.0 Automatic Front 04-May Left wheel Silver 4
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
19232 45798355 8467 - MERCEDES-BENZ CLK 200 1999 Coupe Yes CNG 2.0 Turbo 300000 km 4.0 Manual Rear 02-Mar Left wheel Silver 5
19233 45778856 15681 831 HYUNDAI Sonata 2011 Sedan Yes Petrol 2.4 161600 km 4.0 Tiptronic Front 04-May Left wheel Red 8
19234 45804997 26108 836 HYUNDAI Tucson 2010 Jeep Yes Diesel 2 116365 km 4.0 Automatic Front 04-May Left wheel Grey 4
19235 45793526 5331 1288 CHEVROLET Captiva 2007 Jeep Yes Diesel 2 51258 km 4.0 Automatic Front 04-May Left wheel Black 4
19236 45813273 470 753 HYUNDAI Sonata 2012 Sedan Yes Hybrid 2.4 186923 km 4.0 Automatic Front 04-May Left wheel White 12

19237 rows × 18 columns

In [64]:
auto.dtypes
Out[64]:
ID                    int64
Price                 int64
Levy                 object
Manufacturer         object
Model                object
Prod. year            int64
Category             object
Leather interior     object
Fuel type            object
Engine volume        object
Mileage              object
Cylinders           float64
Gear box type        object
Drive wheels         object
Doors                object
Wheel                object
Color                object
Airbags               int64
dtype: object

Магазины

Информация о колонках

  • Store ID: уникальный идентификатор конкретного магазина (индекс) (int)
  • Store_Area: физическая площадь магазина в квадратных ярдах (int)
  • Items_Available: количество различных товаров, доступных в соответствующем магазине (int)
  • Daily_Customer_Count: среднее количество клиентов, посещающих магазины за месяц (int)
  • Store_Sales: объем продаж (в долларах США), полученный магазинами (int)

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

In [65]:
shop = pd.read_csv("Stores.csv")

shop
Out[65]:
Store ID Store_Area Items_Available Daily_Customer_Count Store_Sales
0 1 1659 1961 530 66490
1 2 1461 1752 210 39820
2 3 1340 1609 720 54010
3 4 1451 1748 620 53730
4 5 1770 2111 450 46620
... ... ... ... ... ...
891 892 1582 1910 1080 66390
892 893 1387 1663 850 82080
893 894 1200 1436 1060 76440
894 895 1299 1560 770 96610
895 896 1174 1429 1110 54340

896 rows × 5 columns

In [66]:
shop.dtypes
Out[66]:
Store ID                int64
Store_Area              int64
Items_Available         int64
Daily_Customer_Count    int64
Store_Sales             int64
dtype: object

3. Провести анализ содержимого каждого набора данных. Что является объектом/объектами наблюдения? Каковы атрибуты объектов? Есть ли связи между объектами?

  1. Датасет о риске инсульта

Объект наблюдения: Пациенты.

Атрибуты перечисленны выше.

  1. Датасет с ценами автомобилей

Объект наблюдения: Автомобили.

Атрибуты перечисленны выше.

  1. Датасет супермакета

Объект наблюдения: Магазины супермаркета.

Атрибуты перечисленны выше.

4. Привести примеры бизнес-целей, для достижения которых могут подойти выбранные наборы данных. Каков эффект для бизнеса?

  1. Датасет о риске инсульта

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

Эффект для бизнеса:

Улучшение здоровья пациентов: Снижение числа инсультов за счет раннего выявления рисков.

Снижение затрат: Уменьшение расходов на лечение инсульта и реабилитацию.

  1. Датасет для прогнозирования цен на автомобили

Бизнес-цель: Оптимизация ценообразования и улучшение стратегии продаж автомобилей.

Эффект для бизнеса:

Увеличение прибыли: Установка конкурентоспособных цен на автомобили на основе анализа данных.

Лучшее планирование запасов: Снижение излишков и оптимизация поставок.

  1. Датасет супермаркета

Бизнес-цель: Оптимизация ассортимента и улучшение обслуживания клиентов на основе анализа посещаемости и продаж.

Эффект для бизнеса:

Увеличение объема продаж: Подбор товаров, наиболее популярных среди клиентов. Снижение затрат: Оптимизация площади магазина и распределения товаров. Повышение клиентской удовлетворенности: Улучшение опыта покупок за счет более эффективной организации товаров и обслуживания.

5. Привести примеры целей технического проекта для каждой выделенной ранее бизнес-цели. Что поступает на вход, что является целевым признаком?

  1. Датасет о риске инсульта

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

Цель технического проекта: Создание модели машинного обучения для прогнозирования вероятности инсульта.

Входные данные:

Пол Возраст Наличие гипертензии Наличие сердечных заболеваний Статус брака Тип работы Тип проживания Средний уровень глюкозы Индекс массы тела Статус курения и так далее

Целевой признак: Наличие инсульта (stroke).

  1. Датасет для прогнозирования цен на автомобили

Бизнес-цель: Оптимизация ценообразования и улучшение стратегии продаж автомобилей.

Цель технического проекта: Построение модели для предсказания цены автомобиля на основе характеристик.

Входные данные:

Производитель Модель Год производства Категория Налог Наличие кожаного салона Тип топлива Рабочий объем двигателя Пробег Количество цилиндров Тип коробки передач и так далее

Целевой признак: Цена автомобиля (Price).

  1. Датасет супермаркета

Бизнес-цель: Оптимизация ассортимента и улучшение обслуживания клиентов.

Цель технического проекта: Разработка аналитической платформы для анализа посещаемости и продаж.

Входные данные:

Физическая площадь магазина Количество доступных товаров Среднее количество клиентов Объем продаж и так далее

Целевой признак: Объем продаж (Store_Sales)

6. Определить проблемы выбранных наборов данных: зашумленность, смещение, актуальность, выбросы, просачивание данных.

7. Привести примеры решения обнаруженных проблем для каждого набора данных

In [67]:
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt

# 1. Проверка на зашумленность ---- количество пропусков в процентах от общего кол-ва
def check_noise(dataframe):
    total_values = dataframe.size
    missing_values = dataframe.isnull().sum().sum()
    noise_percentage = (missing_values / total_values) * 100
    return f"Зашумленность: {noise_percentage:.2f}%"

# 2. Проверка на смещение ----- объем уникальных значений внутри определнной колонки 
def check_bias(dataframe, target_column):
    if target_column in dataframe.columns:
        unique_values = dataframe[target_column].nunique()
        total_values = len(dataframe)
        bias_percentage = (unique_values / total_values) * 100
        return f"Смещение по {target_column}: {bias_percentage:.2f}% уникальных значений"
    return "Целевой признак не найден."

# 3. Проверка на дубликаты
def check_duplicates(dataframe):
    duplicate_percentage = dataframe.duplicated().mean() * 100
    return f"Количество дубликатов: {duplicate_percentage:.2f}%"

# 4. Проверка на выбросы
def check_outliers(dataframe, column):
    if column in dataframe.columns:
        Q1 = dataframe[column].quantile(0.25)
        Q3 = dataframe[column].quantile(0.75)
        IQR = Q3 - Q1
        lower_bound = Q1 - 1.5 * IQR
        upper_bound = Q3 + 1.5 * IQR
        outlier_count = dataframe[(dataframe[column] < lower_bound) | (dataframe[column] > upper_bound)].shape[0]
        total_count = dataframe.shape[0]
        outlier_percentage = (outlier_count / total_count) * 100
        return f"Выбросы по {column}: {outlier_percentage:.2f}%"
    return f"Признак {column} не найден."

# 5. Проверка на просачивание данных
def check_data_leakage(dataframe, target_column):
    if target_column in dataframe.columns:
        correlation_matrix = dataframe.select_dtypes(include=[np.number]).corr()
        leakage_info = correlation_matrix[target_column].abs().nlargest(10)
        leakage_report = ", ".join([f"{feature}: {value:.2f}" for feature, value in leakage_info.items() if feature != target_column])
        return f"Признаки просачивания данных: {leakage_report}"
    return "Целевой признак не найден."
In [68]:
noise_columns = check_noise(strokes)
bias_info = check_bias(strokes, 'avg_glucose_level') 
duplicate_count = check_duplicates(strokes)
outliers_data = check_outliers(strokes, 'avg_glucose_level')  
leakage_info = check_data_leakage(strokes, 'stroke') 

print(noise_columns)
print(bias_info)
print(duplicate_count)
print(outliers_data)
print(leakage_info)
Зашумленность: 0.33%
Смещение по avg_glucose_level: 77.87% уникальных значений
Количество дубликатов: 0.00%
Выбросы по avg_glucose_level: 12.27%
Признаки просачивания данных: age: 0.25, heart_disease: 0.13, avg_glucose_level: 0.13, hypertension: 0.13, bmi: 0.04, id: 0.01
In [69]:
##Машины
noise_columns = check_noise(auto)
bias_info = check_bias(auto, 'Price') 
duplicate_count = check_duplicates(auto)
outliers_data = check_outliers(auto, 'Prod. year')  
leakage_info = check_data_leakage(auto, 'Airbags') 

print(noise_columns)
print(bias_info)
print(duplicate_count)
print(outliers_data)
print(leakage_info)
Зашумленность: 0.00%
Смещение по Price: 12.03% уникальных значений
Количество дубликатов: 1.63%
Выбросы по Prod. year: 5.10%
Признаки просачивания данных: Prod. year: 0.24, Cylinders: 0.18, ID: 0.02, Price: 0.01
In [70]:
noise_columns = check_noise(shop)
bias_info = check_bias(shop, 'Items_Available') 
duplicate_count = check_duplicates(shop)
outliers_data = check_outliers(shop, 'Store_Sales')  
leakage_info = check_data_leakage(shop, 'Daily_Customer_Count') 

print(noise_columns)
print(bias_info)
print(duplicate_count)
print(outliers_data)
print(leakage_info)
Зашумленность: 0.00%
Смещение по Items_Available: 68.75% уникальных значений
Количество дубликатов: 0.00%
Выбросы по Store_Sales: 0.11%
Признаки просачивания данных: Store_Area: 0.04, Items_Available: 0.04, Store ID : 0.01, Store_Sales: 0.01

9. Устранить проблему пропущенных данных. Для каждого набора данных использовать разные методы: удаление, подстановка константного значения (0 или подобное), подстановка среднего значения

In [71]:
# Инсульт

strokes.isnull().sum()
Out[71]:
id                     0
gender                 0
age                    0
hypertension           0
heart_disease          0
ever_married           0
work_type              0
Residence_type         0
avg_glucose_level      0
bmi                  201
smoking_status         0
stroke                 0
dtype: int64
In [72]:
strokes['bmi'] = strokes['bmi'].fillna(strokes['bmi'].mean())
In [73]:
strokes.isnull().sum()
Out[73]:
id                   0
gender               0
age                  0
hypertension         0
heart_disease        0
ever_married         0
work_type            0
Residence_type       0
avg_glucose_level    0
bmi                  0
smoking_status       0
stroke               0
dtype: int64
In [74]:
auto.isnull().sum()
Out[74]:
ID                  0
Price               0
Levy                0
Manufacturer        0
Model               0
Prod. year          0
Category            0
Leather interior    0
Fuel type           0
Engine volume       0
Mileage             0
Cylinders           0
Gear box type       0
Drive wheels        0
Doors               0
Wheel               0
Color               0
Airbags             0
dtype: int64
In [75]:
shop.isnull().sum()
Out[75]:
Store ID                0
Store_Area              0
Items_Available         0
Daily_Customer_Count    0
Store_Sales             0
dtype: int64
In [76]:
# удалить
shop = shop.dropna()

# заполнить значением
shop['Items_Avialable'] = shop['Items_Avialable'].fillna(5000)

10. Выполнить разбиение каждого набора данных на обучающую, контрольную и тестовую выборки

In [79]:
from sklearn.model_selection import train_test_split
In [80]:
# Разбиение shop
original_shop_size = len(shop)
train_shop, temp_shop = train_test_split(shop, test_size=0.2, random_state=42)
val_shop, test_shop = train_test_split(temp_shop, test_size=0.5, random_state=42)

print("Shop Dataset:")
print(f"Train: {len(train_shop)/original_shop_size*100:.2f}%")
print(f"Validation: {len(val_shop)/original_shop_size*100:.2f}%")
print(f"Test: {len(test_shop)/original_shop_size*100:.2f}%\n")
Shop Dataset:
Train: 79.91%
Validation: 10.04%
Test: 10.04%

In [82]:
# Разбиение strokes
original_strokes_size = len(strokes)
train_strokes, temp_strokes = train_test_split(strokes, test_size=0.2, random_state=42)
val_strokes, test_strokes = train_test_split(temp_strokes, test_size=0.5, random_state=42)

print("Strokes Dataset:")
print(f"Train: {len(train_strokes)/original_strokes_size*100:.2f}%")
print(f"Validation: {len(val_strokes)/original_strokes_size*100:.2f}%")
print(f"Test: {len(test_strokes)/original_strokes_size*100:.2f}%\n")
Strokes Dataset:
Train: 80.00%
Validation: 10.00%
Test: 10.00%

In [83]:
# Разбиение auto
original_auto_size = len(auto)
train_auto, temp_auto = train_test_split(auto, test_size=0.2, random_state=42)
val_auto, test_auto = train_test_split(temp_auto, test_size=0.5, random_state=42)

print("Auto Dataset:")
print(f"Train: {len(train_auto)/original_auto_size*100:.2f}%")
print(f"Validation: {len(val_auto)/original_auto_size*100:.2f}%")
print(f"Test: {len(test_auto)/original_auto_size*100:.2f}%")
Auto Dataset:
Train: 80.00%
Validation: 10.00%
Test: 10.00%

11. Оценить сбалансированность выборок для каждого набора данных. Оценить необходимость использования методов приращения (аугментации) данных.

12. Выполнить приращение данных методами выборки с избытком (oversampling) и выборки с недостатком (undersampling). Должны быть представлены примеры реализации обоих методов для выборок каждого набора данных.

In [85]:
def plot_sample_balance(y, sample_name):
    plt.figure(figsize=(8, 5))
    sns.histplot(y, bins=30, kde=True)
    plt.title(f'Распределение целевой переменной для {sample_name}')
    plt.xlabel(sample_name)
    plt.ylabel('Частота')
    plt.show()

# Оценка сбалансированности выборок
plot_sample_balance(train_shop['Store_Sales'], 'Train Shop')
plot_sample_balance(val_shop['Store_Sales'], 'Validation Shop')
plot_sample_balance(test_shop['Store_Sales'], 'Test Shop')
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image

Распределения выборок у данного датасета выглядят схоже. Это говорит о сбалансированности выборок.

In [86]:
plot_sample_balance(train_strokes['stroke'], 'Train Strokes')
plot_sample_balance(val_strokes['stroke'], 'Validation Strokes')
plot_sample_balance(test_strokes['stroke'], 'Test Strokes')
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image

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

In [87]:
plot_sample_balance(train_auto['Price'], 'Train Auto')
plot_sample_balance(val_auto['Price'], 'Validation Auto')
plot_sample_balance(test_auto['Price'], 'Test Auto')
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image

Распределения выборок у данного датасета выглядят схоже. Это говорит о сбалансированности выборок. Однако в тренировочной выборке значительно больший размах значений

12. Выполнить приращение данных методами выборки с избытком (oversampling) и выборки с недостатком (undersampling). Должны быть представлены примеры реализации обоих методов для выборок каждого набора данных

Инсультики

In [90]:
from imblearn.over_sampling import SMOTE

X_strokes = strokes.drop('stroke', axis=1)
y_strokes = strokes['stroke']

# Кодирование категориальных признаков
for column in X_strokes.select_dtypes(include=['object']).columns:
    X_strokes[column] = X_strokes[column].astype('category').cat.codes

# Теперь применяем SMOTE
smote = SMOTE(random_state=42)
X_resampled_strokes, y_resampled_strokes = smote.fit_resample(X_strokes, y_strokes)

# Получаем результаты
print(f'После oversampling (strokes): {pd.Series(y_resampled_strokes).value_counts()}')
После oversampling (strokes): stroke
1    4861
0    4861
Name: count, dtype: int64
In [92]:
from imblearn.under_sampling import RandomUnderSampler

# Undersampling для strokes
undersample = RandomUnderSampler(random_state=42)
X_under_strokes, y_under_strokes = undersample.fit_resample(X_strokes, y_strokes)

print(f'После undersampling (strokes): {pd.Series(y_under_strokes).value_counts()}')
После undersampling (strokes): stroke
0    249
1    249
Name: count, dtype: int64

Машины

In [ ]:
from imblearn.over_sampling import SMOTE

X_strokes = strokes.drop('stroke', axis=1)
y_strokes = strokes['stroke']

# Кодирование категориальных признаков
for column in X_strokes.select_dtypes(include=['object']).columns:
    X_strokes[column] = X_strokes[column].astype('category').cat.codes

# Теперь применяем SMOTE
smote = SMOTE(random_state=42)
X_resampled_strokes, y_resampled_strokes = smote.fit_resample(X_strokes, y_strokes)

# Получаем результаты
print(f'После oversampling (strokes): {pd.Series(y_resampled_strokes).value_counts()}')
После oversampling (strokes): stroke
1    4861
0    4861
Name: count, dtype: int64
In [ ]:
from imblearn.under_sampling import RandomUnderSampler

# Undersampling для strokes
undersample = RandomUnderSampler(random_state=42)
X_under_strokes, y_under_strokes = undersample.fit_resample(X_strokes, y_strokes)

print(f'После undersampling (strokes): {pd.Series(y_under_strokes).value_counts()}')
После undersampling (strokes): stroke
0    249
1    249
Name: count, dtype: int64

Магазины

In [93]:
X_shop = shop.drop('Store_Sales', axis=1)
y_shop = shop['Store_Sales']

# Кодирование категориальных признаков
for column in X_shop.select_dtypes(include=['object']).columns:
    X_shop[column] = X_shop[column].astype('category').cat.codes

# Теперь применяем SMOTE
smote = SMOTE(random_state=42)
X_resampled_shop, y_resampled_shop = smote.fit_resample(X_shop, y_shop)

# Получаем результаты
print(f'После oversampling (strokes): {pd.Series(y_resampled_shop).value_counts()}')
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
c:\Users\Матевос\Desktop\ИИ.Дырночкин\ai\lab2\lab2.ipynb Cell 55 line 1
      <a href='vscode-notebook-cell:/c%3A/Users/%D0%9C%D0%B0%D1%82%D0%B5%D0%B2%D0%BE%D1%81/Desktop/%D0%98%D0%98.%D0%94%D1%8B%D1%80%D0%BD%D0%BE%D1%87%D0%BA%D0%B8%D0%BD/ai/lab2/lab2.ipynb#Y151sZmlsZQ%3D%3D?line=7'>8</a> # Теперь применяем SMOTE
      <a href='vscode-notebook-cell:/c%3A/Users/%D0%9C%D0%B0%D1%82%D0%B5%D0%B2%D0%BE%D1%81/Desktop/%D0%98%D0%98.%D0%94%D1%8B%D1%80%D0%BD%D0%BE%D1%87%D0%BA%D0%B8%D0%BD/ai/lab2/lab2.ipynb#Y151sZmlsZQ%3D%3D?line=8'>9</a> smote = SMOTE(random_state=42)
---> <a href='vscode-notebook-cell:/c%3A/Users/%D0%9C%D0%B0%D1%82%D0%B5%D0%B2%D0%BE%D1%81/Desktop/%D0%98%D0%98.%D0%94%D1%8B%D1%80%D0%BD%D0%BE%D1%87%D0%BA%D0%B8%D0%BD/ai/lab2/lab2.ipynb#Y151sZmlsZQ%3D%3D?line=9'>10</a> X_resampled_shop, y_resampled_shop = smote.fit_resample(X_shop, y_shop)
     <a href='vscode-notebook-cell:/c%3A/Users/%D0%9C%D0%B0%D1%82%D0%B5%D0%B2%D0%BE%D1%81/Desktop/%D0%98%D0%98.%D0%94%D1%8B%D1%80%D0%BD%D0%BE%D1%87%D0%BA%D0%B8%D0%BD/ai/lab2/lab2.ipynb#Y151sZmlsZQ%3D%3D?line=11'>12</a> # Получаем результаты
     <a href='vscode-notebook-cell:/c%3A/Users/%D0%9C%D0%B0%D1%82%D0%B5%D0%B2%D0%BE%D1%81/Desktop/%D0%98%D0%98.%D0%94%D1%8B%D1%80%D0%BD%D0%BE%D1%87%D0%BA%D0%B8%D0%BD/ai/lab2/lab2.ipynb#Y151sZmlsZQ%3D%3D?line=12'>13</a> print(f'После oversampling (strokes): {pd.Series(y_resampled_shop).value_counts()}')

File c:\Users\Матевос\AppData\Local\Programs\Python\Python312\Lib\site-packages\imblearn\base.py:208, in BaseSampler.fit_resample(self, X, y)
    187 """Resample the dataset.
    188 
    189 Parameters
   (...)
    205     The corresponding label of `X_resampled`.
    206 """
    207 self._validate_params()
--> 208 return super().fit_resample(X, y)

File c:\Users\Матевос\AppData\Local\Programs\Python\Python312\Lib\site-packages\imblearn\base.py:112, in SamplerMixin.fit_resample(self, X, y)
    106 X, y, binarize_y = self._check_X_y(X, y)
    108 self.sampling_strategy_ = check_sampling_strategy(
    109     self.sampling_strategy, y, self._sampling_type
    110 )
--> 112 output = self._fit_resample(X, y)
    114 y_ = (
    115     label_binarize(output[1], classes=np.unique(y)) if binarize_y else output[1]
    116 )
    118 X_, y_ = arrays_transformer.transform(output[0], y_)

File c:\Users\Матевос\AppData\Local\Programs\Python\Python312\Lib\site-packages\imblearn\over_sampling\_smote\base.py:389, in SMOTE._fit_resample(self, X, y)
    386 X_class = _safe_indexing(X, target_class_indices)
    388 self.nn_k_.fit(X_class)
--> 389 nns = self.nn_k_.kneighbors(X_class, return_distance=False)[:, 1:]
    390 X_new, y_new = self._make_samples(
    391     X_class, y.dtype, class_sample, X_class, nns, n_samples, 1.0
    392 )
    393 X_resampled.append(X_new)

File c:\Users\Матевос\AppData\Local\Programs\Python\Python312\Lib\site-packages\sklearn\neighbors\_base.py:834, in KNeighborsMixin.kneighbors(self, X, n_neighbors, return_distance)
    832     else:
    833         inequality_str = "n_neighbors <= n_samples_fit"
--> 834     raise ValueError(
    835         f"Expected {inequality_str}, but "
    836         f"n_neighbors = {n_neighbors}, n_samples_fit = {n_samples_fit}, "
    837         f"n_samples = {X.shape[0]}"  # include n_samples for common tests
    838     )
    840 n_jobs = effective_n_jobs(self.n_jobs)
    841 chunked_results = None

ValueError: Expected n_neighbors <= n_samples_fit, but n_neighbors = 6, n_samples_fit = 1, n_samples = 1
In [ ]:
from imblearn.under_sampling import RandomUnderSampler

# Undersampling для strokes
undersample = RandomUnderSampler(random_state=42)
X_under_strokes, y_under_strokes = undersample.fit_resample(X_strokes, y_strokes)

print(f'После undersampling (strokes): {pd.Series(y_under_strokes).value_counts()}')
После undersampling (strokes): stroke
0    249
1    249
Name: count, dtype: int64

В данном случае у нас есть только один датасет, предназначенный для решения задачи классификации (инсульт). Проблему дисбаланса в нем мы решили применив undersampling & oversampling.

Два остальных датасета не содержат классов, т.к предназначены для решения задачи регрессии (предсказания цен на автомобили или на чек в супермаркете), поэтому выполнять приращение данных не требуется.