AIM-PIbd-31-Teryokhin-A-S/lab_2/lab2.ipynb
2024-10-26 15:34:44 +03:00

40 KiB
Raw Blame History

1. Цены на золото

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

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

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

Объект исследования - данные о торгах золотом на биржах

Проблемная область - прогнозирование цен на золото

In [1]:
import pandas as pd;
data_gold = pd.read_csv("..//static//csv//gold.csv", sep=",")
print('количество колонок: ' + str(data_gold.columns.size))
print('колонки: ' + ', '.join(data_gold.columns))
количество колонок: 81
колонки: Date, Open, High, Low, Close, Adj Close, Volume, SP_open, SP_high, SP_low, SP_close, SP_Ajclose, SP_volume, DJ_open, DJ_high, DJ_low, DJ_close, DJ_Ajclose, DJ_volume, EG_open, EG_high, EG_low, EG_close, EG_Ajclose, EG_volume, EU_Price, EU_open, EU_high, EU_low, EU_Trend, OF_Price, OF_Open, OF_High, OF_Low, OF_Volume, OF_Trend, OS_Price, OS_Open, OS_High, OS_Low, OS_Trend, SF_Price, SF_Open, SF_High, SF_Low, SF_Volume, SF_Trend, USB_Price, USB_Open, USB_High, USB_Low, USB_Trend, PLT_Price, PLT_Open, PLT_High, PLT_Low, PLT_Trend, PLD_Price, PLD_Open, PLD_High, PLD_Low, PLD_Trend, RHO_PRICE, USDI_Price, USDI_Open, USDI_High, USDI_Low, USDI_Volume, USDI_Trend, GDX_Open, GDX_High, GDX_Low, GDX_Close, GDX_Adj Close, GDX_Volume, USO_Open, USO_High, USO_Low, USO_Close, USO_Adj Close, USO_Volume

Получение сведений о пропущенных данных

Типы пропущенных данных:

None - представление пустых данных в Python
NaN - представление пустых данных в Pandas
'' - пустая строка
In [2]:
# Количество пустых значений признаков
print(data_gold.isnull().sum())

print()

# Есть ли пустые значения признаков
print(data_gold.isnull().any())

print()

# Процент пустых значений признаков
for i in data_gold.columns:
    null_rate = data_gold[i].isnull().sum() / len(data_gold) * 100
    if null_rate > 0:
        print(f"{i} процент пустых значений: %{null_rate:.2f}")
Date             0
Open             0
High             0
Low              0
Close            0
                ..
USO_High         0
USO_Low          0
USO_Close        0
USO_Adj Close    0
USO_Volume       0
Length: 81, dtype: int64

Date             False
Open             False
High             False
Low              False
Close            False
                 ...  
USO_High         False
USO_Low          False
USO_Close        False
USO_Adj Close    False
USO_Volume       False
Length: 81, dtype: bool

Итог: пропущеных значений нет

Количество столбцов слишком большое, оставим только самые необходимые

Date: Уникальный идентификатор для каждого торгового дня.
Close: Цена закрытия золота на соответствующую дату.
Volume: Объем торгов золотом на соответствующую дату.
Open: Цена открытия золота на соответствующую дату.
High: Самая высокая зафиксированная цена золота в течение торгового дня.
Low: Самая низкая зафиксированная цена золота в течение торгового дня.
In [6]:
data_gold_reduced = data_gold[['Date', 'Close', 'Volume', 'Open', 'High', 'Low']]

data_gold_reduced.head()
Out[6]:
Date Close Volume Open High Low
0 2011-12-15 152.330002 21521900 154.740005 154.949997 151.710007
1 2011-12-16 155.229996 18124300 154.309998 155.369995 153.899994
2 2011-12-19 154.869995 12547200 155.479996 155.860001 154.360001
3 2011-12-20 156.979996 9136300 156.820007 157.429993 156.580002
4 2011-12-21 157.160004 11996100 156.979996 157.529999 156.130005

Аномальное рапределение будем искать по z-индексу. Z-индекс показывает, насколько далеко значение находится от среднего в стандартных отклонениях. Значения Z-индекса больше 3 или меньше -3 обычно считаются аномальными.

In [9]:
from scipy import stats
# Вычисляем Z-индексы только для числовых столбцов
gold_zscores = data_gold_reduced.select_dtypes(include=['float64', 'int64']).apply(stats.zscore, nan_policy='omit')

# Устанавливаем порог для поиска аномалий
threshold = 3

def find_anomalies(zscores, df):
    for column in zscores.columns:
        # Проверяем, есть ли аномалии в Z-индексах
        anomalies = df[column][(zscores[column].abs() > threshold)]
        if not anomalies.empty:
            print(f"В атрибуте '{column}' обнаружены аномалии: {anomalies.tolist()}")

# Находим аномалии
try:
    print("Аномалии в наборе данных gold:")
    find_anomalies(gold_zscores, data_gold_reduced)

except Exception as e:
    print(f"Произошла ошибка: {e}")
Аномалии в наборе данных gold:
В атрибуте 'Volume' обнаружены аномалии: [28957700, 23355300, 44149000, 28822100, 27399400, 28336900, 23995000, 25148400, 23374100, 30924000, 55601800, 93804200, 25975200, 28872100, 24780000, 24374800, 28341200, 49139000, 26635000, 35782900, 26459600, 24372700, 26810900]

Теперь выполним 10 пункт, разобьем данные на выборки

In [11]:
from sklearn.model_selection import train_test_split
def split_data(df, target_column, test_size=0.2, random_state=42):
    # Разделяем данные на обучающую и временную выборки
    X_train, X_temp, y_train, y_temp = train_test_split(df.drop(columns=[target_column]), 
                                                        df[target_column], 
                                                        test_size=test_size, 
                                                        random_state=random_state)
    # Делим временную выборку на контрольную и тестовую
    X_val, X_test, y_val, y_test = train_test_split(X_temp, y_temp, 
                                                      test_size=0.5, 
                                                      random_state=random_state)
    
    return X_train, X_val, X_test, y_train, y_val, y_test

gold_train, gold_val, gold_test, gold_train_labels, gold_val_labels, gold_test_labels = split_data(data_gold_reduced, 'Close')

def check_balance(y_train, y_val, y_test):
    print("Обучающая выборка:")
    print(y_train.value_counts(normalize=True))
    print("\nКонтрольная выборка:")
    print(y_val.value_counts(normalize=True))
    print("\nТестовая выборка:")
    print(y_test.value_counts(normalize=True))

print("Набор данных gold:")
check_balance(gold_train_labels, gold_val_labels, gold_test_labels)
Набор данных gold:
Обучающая выборка:
Close
122.209999    0.002911
114.769997    0.002911
116.769997    0.002911
115.779999    0.002911
115.379997    0.002183
                ...   
160.779999    0.000728
161.600006    0.000728
118.180000    0.000728
104.019997    0.000728
118.589996    0.000728
Name: proportion, Length: 1151, dtype: float64

Контрольная выборка:
Close
119.180000    0.011628
121.580002    0.011628
122.419998    0.011628
115.800003    0.011628
122.820000    0.011628
                ...   
107.339996    0.005814
125.459999    0.005814
159.570007    0.005814
128.990005    0.005814
136.419998    0.005814
Name: proportion, Length: 166, dtype: float64

Тестовая выборка:
Close
113.419998    0.011628
159.570007    0.005814
156.990005    0.005814
159.429993    0.005814
173.610001    0.005814
                ...   
118.820000    0.005814
119.500000    0.005814
164.419998    0.005814
122.320000    0.005814
169.309998    0.005814
Name: proportion, Length: 171, dtype: float64

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

Для этого набора данных не надо использовать преращение данных так как задача не на классификацию.

2. Диабет у женщин Пима

Этот набор данных изначально был получен из Национального института диабета, заболеваний пищеварительной системы и почек. Целью набора данных является диагностическое прогнозирование наличия или отсутствия у пациента диабета на основе определенных диагностических измерений, включенных в набор данных. На выбор этих случаев из более крупной базы данных налагалось несколько ограничений. В частности, все пациенты здесь — женщины в возрасте не менее 21 года индейского происхождения пима.

Проблемная область - предсказание диабета

In [15]:
diabetes = pd.read_csv("..//static//csv//diabetes.csv", sep=",")
print('количество колонок: ' + str(diabetes.columns.size))
print('колонки: ' + ', '.join(diabetes.columns))
количество колонок: 9
колонки: Pregnancies, Glucose, BloodPressure, SkinThickness, Insulin, BMI, DiabetesPedigreeFunction, Age, Outcome

Получение сведений о пропущенных данных

Типы пропущенных данных:

None - представление пустых данных в Python
NaN - представление пустых данных в Pandas
'' - пустая строка
In [16]:
# Количество пустых значений признаков
print(diabetes.isnull().sum())

print()

# Есть ли пустые значения признаков
print(diabetes.isnull().any())

print()

# Процент пустых значений признаков
for i in diabetes.columns:
    null_rate = diabetes[i].isnull().sum() / len(diabetes) * 100
    if null_rate > 0:
        print(f"{i} процент пустых значений: %{null_rate:.2f}")
Pregnancies                 0
Glucose                     0
BloodPressure               0
SkinThickness               0
Insulin                     0
BMI                         0
DiabetesPedigreeFunction    0
Age                         0
Outcome                     0
dtype: int64

Pregnancies                 False
Glucose                     False
BloodPressure               False
SkinThickness               False
Insulin                     False
BMI                         False
DiabetesPedigreeFunction    False
Age                         False
Outcome                     False
dtype: bool

Итог: пропущенных данных нет

In [17]:
print(diabetes.describe())
       Pregnancies     Glucose  BloodPressure  SkinThickness     Insulin  \
count   768.000000  768.000000     768.000000     768.000000  768.000000   
mean      3.845052  120.894531      69.105469      20.536458   79.799479   
std       3.369578   31.972618      19.355807      15.952218  115.244002   
min       0.000000    0.000000       0.000000       0.000000    0.000000   
25%       1.000000   99.000000      62.000000       0.000000    0.000000   
50%       3.000000  117.000000      72.000000      23.000000   30.500000   
75%       6.000000  140.250000      80.000000      32.000000  127.250000   
max      17.000000  199.000000     122.000000      99.000000  846.000000   

              BMI  DiabetesPedigreeFunction         Age     Outcome  
count  768.000000                768.000000  768.000000  768.000000  
mean    31.992578                  0.471876   33.240885    0.348958  
std      7.884160                  0.331329   11.760232    0.476951  
min      0.000000                  0.078000   21.000000    0.000000  
25%     27.300000                  0.243750   24.000000    0.000000  
50%     32.000000                  0.372500   29.000000    0.000000  
75%     36.600000                  0.626250   41.000000    1.000000  
max     67.100000                  2.420000   81.000000    1.000000  

Теперь проверим данные на аномалии

In [29]:
# Вычисляем Z-индексы только для числовых столбцов
diabetes_zscores = diabetes.select_dtypes(include=['float64', 'int64']).apply(stats.zscore, nan_policy='omit')

# Устанавливаем порог для поиска аномалий
threshold = 3

# Находим аномалии
try:
    print("Аномалии в наборе данных diabetes:")
    find_anomalies(diabetes_zscores, diabetes)

except Exception as e:
    print(f"Произошла ошибка: {e}")
Аномалии в наборе данных diabetes:
В атрибуте 'Pregnancies' обнаружены аномалии: [15, 17, 14, 14]
В атрибуте 'Glucose' обнаружены аномалии: [0, 0, 0, 0, 0]
В атрибуте 'BloodPressure' обнаружены аномалии: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
В атрибуте 'SkinThickness' обнаружены аномалии: [99]
В атрибуте 'Insulin' обнаружены аномалии: [543, 846, 495, 485, 495, 478, 744, 680, 545, 465, 579, 474, 480, 600, 440, 540, 480, 510]
В атрибуте 'BMI' обнаружены аномалии: [0.0, 0.0, 0.0, 0.0, 0.0, 67.1, 0.0, 0.0, 59.4, 0.0, 0.0, 57.3, 0.0, 0.0]
В атрибуте 'DiabetesPedigreeFunction' обнаружены аномалии: [2.288, 1.893, 1.781, 2.329, 1.476, 2.137, 1.731, 1.6, 2.42, 1.699, 1.698]
В атрибуте 'Age' обнаружены аномалии: [69, 72, 81, 70, 69]

Теперь выполним разбиение данных

In [20]:
diabetes_train, diabetes_val, diabetes_test, diabetes_train_labels, diabetes_val_labels, diabetes_test_labels = split_data(diabetes, 'Outcome')

check_balance(diabetes_train_labels, diabetes_val_labels, diabetes_test_labels)
Обучающая выборка:
Outcome
0    0.653094
1    0.346906
Name: proportion, dtype: float64

Контрольная выборка:
Outcome
0    0.675325
1    0.324675
Name: proportion, dtype: float64

Тестовая выборка:
Outcome
0    0.61039
1    0.38961
Name: proportion, dtype: float64

В этом наборе данных наблюдается дисбаланс, 0 тип составляет около 65%, а 1 тип около 35%. В этом случае лучше использовать метод oversampling.

In [21]:
from imblearn.over_sampling import RandomOverSampler

X_diabetes = diabetes.drop('Outcome', axis=1)
y_diabetes = diabetes['Outcome']

# Oversampling
ros_diabetes = RandomOverSampler(random_state=42)
X_diabetes_resampled, y_diabetes_resampled = ros_diabetes.fit_resample(X_diabetes, y_diabetes)
diabetes_resampled = pd.DataFrame(X_diabetes_resampled, columns=X_diabetes.columns)
diabetes_resampled['Outcome'] = y_diabetes_resampled

print("\nOversampling для Diabetes:")
print(diabetes_resampled['Outcome'].value_counts())
Oversampling для Diabetes:
Outcome
1    500
0    500
Name: count, dtype: int64

3. Индикаторы инсульта

По данным Всемирной организации здравоохранения (ВОЗ), инсульт является второй по значимости причиной смертности во всем мире, на его долю приходится примерно 11% от общего числа смертей. Этот набор данных используется для прогнозирования вероятности инсульта у пациента на основе таких входных параметров, как пол, возраст, различные заболевания и статус курильщика. Каждая строка данных содержит соответствующую информацию о пациенте.

Объект исследования - реальные данные о пациентах

Проблемная область - предсказание инсульта

In [23]:
healthcare = pd.read_csv("..//static//csv//healthcare-dataset-stroke-data.csv", sep=",")
print('количество колонок: ' + str(healthcare.columns.size))
print('колонки: ' + ', '.join(healthcare.columns))
количество колонок: 12
колонки: id, gender, age, hypertension, heart_disease, ever_married, work_type, Residence_type, avg_glucose_level, bmi, smoking_status, stroke

Получение сведений о пропущенных данных

Типы пропущенных данных:

None - представление пустых данных в Python
NaN - представление пустых данных в Pandas
'' - пустая строка
In [24]:
# Количество пустых значений признаков
print(healthcare.isnull().sum())

print()

# Есть ли пустые значения признаков
print(healthcare.isnull().any())

print()

# Процент пустых значений признаков
for i in healthcare.columns:
    null_rate = healthcare[i].isnull().sum() / len(healthcare) * 100
    if null_rate > 0:
        print(f"{i} процент пустых значений: %{null_rate:.2f}")
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

id                   False
gender               False
age                  False
hypertension         False
heart_disease        False
ever_married         False
work_type            False
Residence_type       False
avg_glucose_level    False
bmi                   True
smoking_status       False
stroke               False
dtype: bool

bmi процент пустых значений: %3.93

Для столбца bmi используем заполнение данных на "Unknown" для пустых значений.

In [28]:
healthcare['bmi'] = healthcare['bmi'].fillna('Unknown')

print(healthcare.describe())
                 id          age  hypertension  heart_disease  \
count   5110.000000  5110.000000   5110.000000    5110.000000   
mean   36517.829354    43.226614      0.097456       0.054012   
std    21161.721625    22.612647      0.296607       0.226063   
min       67.000000     0.080000      0.000000       0.000000   
25%    17741.250000    25.000000      0.000000       0.000000   
50%    36932.000000    45.000000      0.000000       0.000000   
75%    54682.000000    61.000000      0.000000       0.000000   
max    72940.000000    82.000000      1.000000       1.000000   

       avg_glucose_level       stroke  
count        5110.000000  5110.000000  
mean          106.147677     0.048728  
std            45.283560     0.215320  
min            55.120000     0.000000  
25%            77.245000     0.000000  
50%            91.885000     0.000000  
75%           114.090000     0.000000  
max           271.740000     1.000000  

Проверим данные на аномалии

In [30]:
healthcare_zscores = healthcare.select_dtypes(include=['float64', 'int64']).apply(stats.zscore, nan_policy='omit')

# Устанавливаем порог для поиска аномалий
threshold = 3
# Находим аномалии
try:
    print("\nАномалии в наборе данных healthcare:")
    find_anomalies(healthcare_zscores, healthcare)

except Exception as e:
    print(f"Произошла ошибка: {e}")
Аномалии в наборе данных Healthcare:
В атрибуте 'hypertension' обнаружены аномалии: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
В атрибуте 'heart_disease' обнаружены аномалии: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
В атрибуте 'avg_glucose_level' обнаружены аномалии: [252.72, 243.58, 259.63, 249.31, 263.32, 271.74, 242.52, 250.89, 247.51, 243.53, 242.3, 243.5, 251.6, 247.69, 250.2, 254.6, 254.63, 246.34, 251.46, 267.76, 246.53, 244.28, 251.99, 253.16, 242.84, 249.29, 242.94, 247.48, 266.59, 243.73, 243.59, 250.8, 255.17, 267.61, 260.85, 248.37, 263.56, 247.97, 248.24, 253.93, 254.95, 247.87, 261.67, 256.74, 244.3, 242.62, 243.52, 267.6, 253.86]
В атрибуте 'stroke' обнаружены аномалии: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

Теперь выполним разбиение данных

In [31]:
healthcare_train, healthcare_val, healthcare_test, healthcare_train_labels, healthcare_val_labels, healthcare_test_labels = split_data(healthcare, 'stroke')


check_balance(healthcare_train_labels, healthcare_val_labels, healthcare_test_labels)
Обучающая выборка:
stroke
0    0.954256
1    0.045744
Name: proportion, dtype: float64

Контрольная выборка:
stroke
0    0.939335
1    0.060665
Name: proportion, dtype: float64

Тестовая выборка:
stroke
0    0.939335
1    0.060665
Name: proportion, dtype: float64

В этом наборе данных данные совсем несбалансированы, из-за чего аугментация данных необходима для более точного обучения. В этом наборе используем undersampling.

In [34]:
from imblearn.under_sampling import RandomUnderSampler

X_healthcare = healthcare.drop('stroke', axis=1)
y_healthcare = healthcare['stroke']

rus_healthcare = RandomUnderSampler(random_state=42)
X_healthcare_resampled_under, y_healthcare_resampled_under = rus_healthcare.fit_resample(X_healthcare, y_healthcare)
healthcare_resampled_under = pd.DataFrame(X_healthcare_resampled_under, columns=X_healthcare.columns)
healthcare_resampled_under['stroke'] = y_healthcare_resampled_under

print("\nUndersampling для Healthcare:")
print(healthcare_resampled_under['stroke'].value_counts())
Undersampling для Healthcare:
stroke
0    249
1    249
Name: count, dtype: int64