3299 lines
184 KiB
Plaintext
3299 lines
184 KiB
Plaintext
{
|
||
"cells": [
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"# Данные по инсультам\n",
|
||
"\n",
|
||
"Выведем информацию о столбцах датасета:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 1,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/html": [
|
||
"<div>\n",
|
||
"<style scoped>\n",
|
||
" .dataframe tbody tr th:only-of-type {\n",
|
||
" vertical-align: middle;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .dataframe tbody tr th {\n",
|
||
" vertical-align: top;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .dataframe thead th {\n",
|
||
" text-align: right;\n",
|
||
" }\n",
|
||
"</style>\n",
|
||
"<table border=\"1\" class=\"dataframe\">\n",
|
||
" <thead>\n",
|
||
" <tr style=\"text-align: right;\">\n",
|
||
" <th></th>\n",
|
||
" <th>gender</th>\n",
|
||
" <th>age</th>\n",
|
||
" <th>hypertension</th>\n",
|
||
" <th>heart_disease</th>\n",
|
||
" <th>ever_married</th>\n",
|
||
" <th>work_type</th>\n",
|
||
" <th>Residence_type</th>\n",
|
||
" <th>avg_glucose_level</th>\n",
|
||
" <th>bmi</th>\n",
|
||
" <th>smoking_status</th>\n",
|
||
" <th>stroke</th>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>id</th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" </tr>\n",
|
||
" </thead>\n",
|
||
" <tbody>\n",
|
||
" <tr>\n",
|
||
" <th>9046</th>\n",
|
||
" <td>Male</td>\n",
|
||
" <td>67.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>1</td>\n",
|
||
" <td>Yes</td>\n",
|
||
" <td>Private</td>\n",
|
||
" <td>Urban</td>\n",
|
||
" <td>228.69</td>\n",
|
||
" <td>36.6</td>\n",
|
||
" <td>formerly smoked</td>\n",
|
||
" <td>1</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>51676</th>\n",
|
||
" <td>Female</td>\n",
|
||
" <td>61.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>Yes</td>\n",
|
||
" <td>Self-employed</td>\n",
|
||
" <td>Rural</td>\n",
|
||
" <td>202.21</td>\n",
|
||
" <td>NaN</td>\n",
|
||
" <td>never smoked</td>\n",
|
||
" <td>1</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>31112</th>\n",
|
||
" <td>Male</td>\n",
|
||
" <td>80.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>1</td>\n",
|
||
" <td>Yes</td>\n",
|
||
" <td>Private</td>\n",
|
||
" <td>Rural</td>\n",
|
||
" <td>105.92</td>\n",
|
||
" <td>32.5</td>\n",
|
||
" <td>never smoked</td>\n",
|
||
" <td>1</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>60182</th>\n",
|
||
" <td>Female</td>\n",
|
||
" <td>49.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>Yes</td>\n",
|
||
" <td>Private</td>\n",
|
||
" <td>Urban</td>\n",
|
||
" <td>171.23</td>\n",
|
||
" <td>34.4</td>\n",
|
||
" <td>smokes</td>\n",
|
||
" <td>1</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>1665</th>\n",
|
||
" <td>Female</td>\n",
|
||
" <td>79.0</td>\n",
|
||
" <td>1</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>Yes</td>\n",
|
||
" <td>Self-employed</td>\n",
|
||
" <td>Rural</td>\n",
|
||
" <td>174.12</td>\n",
|
||
" <td>24.0</td>\n",
|
||
" <td>never smoked</td>\n",
|
||
" <td>1</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>...</th>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>18234</th>\n",
|
||
" <td>Female</td>\n",
|
||
" <td>80.0</td>\n",
|
||
" <td>1</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>Yes</td>\n",
|
||
" <td>Private</td>\n",
|
||
" <td>Urban</td>\n",
|
||
" <td>83.75</td>\n",
|
||
" <td>NaN</td>\n",
|
||
" <td>never smoked</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>44873</th>\n",
|
||
" <td>Female</td>\n",
|
||
" <td>81.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>Yes</td>\n",
|
||
" <td>Self-employed</td>\n",
|
||
" <td>Urban</td>\n",
|
||
" <td>125.20</td>\n",
|
||
" <td>40.0</td>\n",
|
||
" <td>never smoked</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>19723</th>\n",
|
||
" <td>Female</td>\n",
|
||
" <td>35.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>Yes</td>\n",
|
||
" <td>Self-employed</td>\n",
|
||
" <td>Rural</td>\n",
|
||
" <td>82.99</td>\n",
|
||
" <td>30.6</td>\n",
|
||
" <td>never smoked</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>37544</th>\n",
|
||
" <td>Male</td>\n",
|
||
" <td>51.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>Yes</td>\n",
|
||
" <td>Private</td>\n",
|
||
" <td>Rural</td>\n",
|
||
" <td>166.29</td>\n",
|
||
" <td>25.6</td>\n",
|
||
" <td>formerly smoked</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>44679</th>\n",
|
||
" <td>Female</td>\n",
|
||
" <td>44.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>Yes</td>\n",
|
||
" <td>Govt_job</td>\n",
|
||
" <td>Urban</td>\n",
|
||
" <td>85.28</td>\n",
|
||
" <td>26.2</td>\n",
|
||
" <td>Unknown</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" </tbody>\n",
|
||
"</table>\n",
|
||
"<p>5110 rows × 11 columns</p>\n",
|
||
"</div>"
|
||
],
|
||
"text/plain": [
|
||
" gender age hypertension heart_disease ever_married work_type \\\n",
|
||
"id \n",
|
||
"9046 Male 67.0 0 1 Yes Private \n",
|
||
"51676 Female 61.0 0 0 Yes Self-employed \n",
|
||
"31112 Male 80.0 0 1 Yes Private \n",
|
||
"60182 Female 49.0 0 0 Yes Private \n",
|
||
"1665 Female 79.0 1 0 Yes Self-employed \n",
|
||
"... ... ... ... ... ... ... \n",
|
||
"18234 Female 80.0 1 0 Yes Private \n",
|
||
"44873 Female 81.0 0 0 Yes Self-employed \n",
|
||
"19723 Female 35.0 0 0 Yes Self-employed \n",
|
||
"37544 Male 51.0 0 0 Yes Private \n",
|
||
"44679 Female 44.0 0 0 Yes Govt_job \n",
|
||
"\n",
|
||
" Residence_type avg_glucose_level bmi smoking_status stroke \n",
|
||
"id \n",
|
||
"9046 Urban 228.69 36.6 formerly smoked 1 \n",
|
||
"51676 Rural 202.21 NaN never smoked 1 \n",
|
||
"31112 Rural 105.92 32.5 never smoked 1 \n",
|
||
"60182 Urban 171.23 34.4 smokes 1 \n",
|
||
"1665 Rural 174.12 24.0 never smoked 1 \n",
|
||
"... ... ... ... ... ... \n",
|
||
"18234 Urban 83.75 NaN never smoked 0 \n",
|
||
"44873 Urban 125.20 40.0 never smoked 0 \n",
|
||
"19723 Rural 82.99 30.6 never smoked 0 \n",
|
||
"37544 Rural 166.29 25.6 formerly smoked 0 \n",
|
||
"44679 Urban 85.28 26.2 Unknown 0 \n",
|
||
"\n",
|
||
"[5110 rows x 11 columns]"
|
||
]
|
||
},
|
||
"execution_count": 1,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"import pandas as pd\n",
|
||
"from sklearn import set_config\n",
|
||
"\n",
|
||
"set_config(transform_output=\"pandas\")\n",
|
||
"\n",
|
||
"random_state=9\n",
|
||
"\n",
|
||
"df = pd.read_csv(\"./csv/option4.csv\", index_col=\"id\")\n",
|
||
"\n",
|
||
"df"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### Бизнес-цели\n",
|
||
"#### Классификация\n",
|
||
"##### Цель: сделать модель, которая на основе данных про здоровье, образ жизни и соцдем-факторы будет предсказывать риск инсульта.\n",
|
||
"\n",
|
||
"Применение:\n",
|
||
"Для врачей: чтобы находить пациентов с высоким риском и вовремя их спасать.\n",
|
||
"Для медсистем: можно встроить в карты пациентов, чтобы система сама предупреждала врача.\n",
|
||
"Для людей: повышать осведомленность о факторах риска и как их избежать.\n",
|
||
"\n",
|
||
"#### Регрессия\n",
|
||
"##### Цель: сделать модель, которая будет предсказывать уровень глюкозы на основе тех же факторов. Поможет отслеживать изменения и оценивать риски.\n",
|
||
"\n",
|
||
"Применение:\n",
|
||
"Для врачей: находить пациентов с риском диабета и другими проблемами, чтобы сразу назначать профилактику.\n",
|
||
"Для медсистем: встроить в записи пациентов, чтобы врачи видели уровень глюкозы даже без лабораторий.\n",
|
||
"Для населения: обучать, как lifestyle влияет на глюкозу, и рекомендовать изменения.\n",
|
||
"\n",
|
||
"### Качество моделей\n",
|
||
"#### Классификация (инсульт):\n",
|
||
"\n",
|
||
"Признаки норм: возраст, гипертония, сердце — инфа полезная, модель будет неплохо различать риск.\n",
|
||
"Проблемы: нет данных про гены, детальную историю болезней, питание, физнагрузки. Это режет потолок точности.\n",
|
||
"\n",
|
||
"#### Регрессия (глюкоза):\n",
|
||
"Признаки норм: возраст, курение, давление — связь с глюкозой есть, что-то предскажет.\n",
|
||
"Проблемы: не хватает данных про еду, активность, гормоны, поэтому точность ограничена."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Классификация\n",
|
||
"\n",
|
||
"Разделим набор данных на на обучающую и тестовые выборки (80/20). Целевой признак - stroke"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 2,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"from typing import Tuple\n",
|
||
"from pandas import DataFrame\n",
|
||
"from sklearn.model_selection import train_test_split\n",
|
||
"\n",
|
||
"def split_stratified_into_train_val_test(\n",
|
||
" df_input,\n",
|
||
" stratify_colname=\"y\",\n",
|
||
" frac_train=0.6,\n",
|
||
" frac_val=0.15,\n",
|
||
" frac_test=0.25,\n",
|
||
" random_state=None,\n",
|
||
") -> Tuple[DataFrame, DataFrame, DataFrame, DataFrame, DataFrame, DataFrame]:\n",
|
||
" \"\"\"\n",
|
||
" Splits a Pandas dataframe into three subsets (train, val, and test)\n",
|
||
" following fractional ratios provided by the user, where each subset is\n",
|
||
" stratified by the values in a specific column (that is, each subset has\n",
|
||
" the same relative frequency of the values in the column). It performs this\n",
|
||
" splitting by running train_test_split() twice.\n",
|
||
"\n",
|
||
" Parameters\n",
|
||
" ----------\n",
|
||
" df_input : Pandas dataframe\n",
|
||
" Input dataframe to be split.\n",
|
||
" stratify_colname : str\n",
|
||
" The name of the column that will be used for stratification. Usually\n",
|
||
" this column would be for the label.\n",
|
||
" frac_train : float\n",
|
||
" frac_val : float\n",
|
||
" frac_test : float\n",
|
||
" The ratios with which the dataframe will be split into train, val, and\n",
|
||
" test data. The values should be expressed as float fractions and should\n",
|
||
" sum to 1.0.\n",
|
||
" random_state : int, None, or RandomStateInstance\n",
|
||
" Value to be passed to train_test_split().\n",
|
||
"\n",
|
||
" Returns\n",
|
||
" -------\n",
|
||
" df_train, df_val, df_test :\n",
|
||
" Dataframes containing the three splits.\n",
|
||
" \"\"\"\n",
|
||
"\n",
|
||
" if frac_train + frac_val + frac_test != 1.0:\n",
|
||
" raise ValueError(\n",
|
||
" \"fractions %f, %f, %f do not add up to 1.0\"\n",
|
||
" % (frac_train, frac_val, frac_test)\n",
|
||
" )\n",
|
||
"\n",
|
||
" if stratify_colname not in df_input.columns:\n",
|
||
" raise ValueError(\"%s is not a column in the dataframe\" % (stratify_colname))\n",
|
||
"\n",
|
||
" X = df_input # Contains all columns.\n",
|
||
" y = df_input[\n",
|
||
" [stratify_colname]\n",
|
||
" ] # Dataframe of just the column on which to stratify.\n",
|
||
"\n",
|
||
" # Split original dataframe into train and temp dataframes.\n",
|
||
" df_train, df_temp, y_train, y_temp = train_test_split(\n",
|
||
" X, y, stratify=y, test_size=(1.0 - frac_train), random_state=random_state\n",
|
||
" )\n",
|
||
"\n",
|
||
" if frac_val <= 0:\n",
|
||
" assert len(df_input) == len(df_train) + len(df_temp)\n",
|
||
" return df_train, pd.DataFrame(), df_temp, y_train, pd.DataFrame(), y_temp\n",
|
||
"\n",
|
||
" # Split the temp dataframe into val and test dataframes.\n",
|
||
" relative_frac_test = frac_test / (frac_val + frac_test)\n",
|
||
" df_val, df_test, y_val, y_test = train_test_split(\n",
|
||
" df_temp,\n",
|
||
" y_temp,\n",
|
||
" stratify=y_temp,\n",
|
||
" test_size=relative_frac_test,\n",
|
||
" random_state=random_state,\n",
|
||
" )\n",
|
||
"\n",
|
||
" assert len(df_input) == len(df_train) + len(df_val) + len(df_test)\n",
|
||
" return df_train, df_val, df_test, y_train, y_val, y_test"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 3,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"'X_train'"
|
||
]
|
||
},
|
||
"metadata": {},
|
||
"output_type": "display_data"
|
||
},
|
||
{
|
||
"data": {
|
||
"text/html": [
|
||
"<div>\n",
|
||
"<style scoped>\n",
|
||
" .dataframe tbody tr th:only-of-type {\n",
|
||
" vertical-align: middle;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .dataframe tbody tr th {\n",
|
||
" vertical-align: top;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .dataframe thead th {\n",
|
||
" text-align: right;\n",
|
||
" }\n",
|
||
"</style>\n",
|
||
"<table border=\"1\" class=\"dataframe\">\n",
|
||
" <thead>\n",
|
||
" <tr style=\"text-align: right;\">\n",
|
||
" <th></th>\n",
|
||
" <th>gender</th>\n",
|
||
" <th>age</th>\n",
|
||
" <th>hypertension</th>\n",
|
||
" <th>heart_disease</th>\n",
|
||
" <th>ever_married</th>\n",
|
||
" <th>work_type</th>\n",
|
||
" <th>Residence_type</th>\n",
|
||
" <th>avg_glucose_level</th>\n",
|
||
" <th>bmi</th>\n",
|
||
" <th>smoking_status</th>\n",
|
||
" <th>stroke</th>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>id</th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" </tr>\n",
|
||
" </thead>\n",
|
||
" <tbody>\n",
|
||
" <tr>\n",
|
||
" <th>22159</th>\n",
|
||
" <td>Female</td>\n",
|
||
" <td>54.0</td>\n",
|
||
" <td>1</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>No</td>\n",
|
||
" <td>Private</td>\n",
|
||
" <td>Urban</td>\n",
|
||
" <td>97.06</td>\n",
|
||
" <td>28.5</td>\n",
|
||
" <td>formerly smoked</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>8920</th>\n",
|
||
" <td>Female</td>\n",
|
||
" <td>51.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>Yes</td>\n",
|
||
" <td>Self-employed</td>\n",
|
||
" <td>Rural</td>\n",
|
||
" <td>76.35</td>\n",
|
||
" <td>33.5</td>\n",
|
||
" <td>formerly smoked</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>65507</th>\n",
|
||
" <td>Male</td>\n",
|
||
" <td>33.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>Yes</td>\n",
|
||
" <td>Private</td>\n",
|
||
" <td>Rural</td>\n",
|
||
" <td>55.72</td>\n",
|
||
" <td>38.2</td>\n",
|
||
" <td>never smoked</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>43196</th>\n",
|
||
" <td>Female</td>\n",
|
||
" <td>52.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>Yes</td>\n",
|
||
" <td>Self-employed</td>\n",
|
||
" <td>Urban</td>\n",
|
||
" <td>59.54</td>\n",
|
||
" <td>42.2</td>\n",
|
||
" <td>Unknown</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>59745</th>\n",
|
||
" <td>Female</td>\n",
|
||
" <td>27.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>Yes</td>\n",
|
||
" <td>Private</td>\n",
|
||
" <td>Urban</td>\n",
|
||
" <td>76.74</td>\n",
|
||
" <td>53.9</td>\n",
|
||
" <td>Unknown</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>...</th>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>66546</th>\n",
|
||
" <td>Female</td>\n",
|
||
" <td>20.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>No</td>\n",
|
||
" <td>Private</td>\n",
|
||
" <td>Urban</td>\n",
|
||
" <td>80.08</td>\n",
|
||
" <td>25.1</td>\n",
|
||
" <td>never smoked</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>68798</th>\n",
|
||
" <td>Female</td>\n",
|
||
" <td>58.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>Yes</td>\n",
|
||
" <td>Private</td>\n",
|
||
" <td>Rural</td>\n",
|
||
" <td>59.86</td>\n",
|
||
" <td>28.0</td>\n",
|
||
" <td>formerly smoked</td>\n",
|
||
" <td>1</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>61409</th>\n",
|
||
" <td>Male</td>\n",
|
||
" <td>32.0</td>\n",
|
||
" <td>1</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>No</td>\n",
|
||
" <td>Govt_job</td>\n",
|
||
" <td>Urban</td>\n",
|
||
" <td>58.24</td>\n",
|
||
" <td>NaN</td>\n",
|
||
" <td>formerly smoked</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>69259</th>\n",
|
||
" <td>Female</td>\n",
|
||
" <td>77.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>Yes</td>\n",
|
||
" <td>Private</td>\n",
|
||
" <td>Rural</td>\n",
|
||
" <td>100.85</td>\n",
|
||
" <td>29.5</td>\n",
|
||
" <td>smokes</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>17231</th>\n",
|
||
" <td>Female</td>\n",
|
||
" <td>24.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>No</td>\n",
|
||
" <td>Private</td>\n",
|
||
" <td>Urban</td>\n",
|
||
" <td>90.42</td>\n",
|
||
" <td>24.3</td>\n",
|
||
" <td>never smoked</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" </tbody>\n",
|
||
"</table>\n",
|
||
"<p>4088 rows × 11 columns</p>\n",
|
||
"</div>"
|
||
],
|
||
"text/plain": [
|
||
" gender age hypertension heart_disease ever_married work_type \\\n",
|
||
"id \n",
|
||
"22159 Female 54.0 1 0 No Private \n",
|
||
"8920 Female 51.0 0 0 Yes Self-employed \n",
|
||
"65507 Male 33.0 0 0 Yes Private \n",
|
||
"43196 Female 52.0 0 0 Yes Self-employed \n",
|
||
"59745 Female 27.0 0 0 Yes Private \n",
|
||
"... ... ... ... ... ... ... \n",
|
||
"66546 Female 20.0 0 0 No Private \n",
|
||
"68798 Female 58.0 0 0 Yes Private \n",
|
||
"61409 Male 32.0 1 0 No Govt_job \n",
|
||
"69259 Female 77.0 0 0 Yes Private \n",
|
||
"17231 Female 24.0 0 0 No Private \n",
|
||
"\n",
|
||
" Residence_type avg_glucose_level bmi smoking_status stroke \n",
|
||
"id \n",
|
||
"22159 Urban 97.06 28.5 formerly smoked 0 \n",
|
||
"8920 Rural 76.35 33.5 formerly smoked 0 \n",
|
||
"65507 Rural 55.72 38.2 never smoked 0 \n",
|
||
"43196 Urban 59.54 42.2 Unknown 0 \n",
|
||
"59745 Urban 76.74 53.9 Unknown 0 \n",
|
||
"... ... ... ... ... ... \n",
|
||
"66546 Urban 80.08 25.1 never smoked 0 \n",
|
||
"68798 Rural 59.86 28.0 formerly smoked 1 \n",
|
||
"61409 Urban 58.24 NaN formerly smoked 0 \n",
|
||
"69259 Rural 100.85 29.5 smokes 0 \n",
|
||
"17231 Urban 90.42 24.3 never smoked 0 \n",
|
||
"\n",
|
||
"[4088 rows x 11 columns]"
|
||
]
|
||
},
|
||
"metadata": {},
|
||
"output_type": "display_data"
|
||
},
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"'y_train'"
|
||
]
|
||
},
|
||
"metadata": {},
|
||
"output_type": "display_data"
|
||
},
|
||
{
|
||
"data": {
|
||
"text/html": [
|
||
"<div>\n",
|
||
"<style scoped>\n",
|
||
" .dataframe tbody tr th:only-of-type {\n",
|
||
" vertical-align: middle;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .dataframe tbody tr th {\n",
|
||
" vertical-align: top;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .dataframe thead th {\n",
|
||
" text-align: right;\n",
|
||
" }\n",
|
||
"</style>\n",
|
||
"<table border=\"1\" class=\"dataframe\">\n",
|
||
" <thead>\n",
|
||
" <tr style=\"text-align: right;\">\n",
|
||
" <th></th>\n",
|
||
" <th>stroke</th>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>id</th>\n",
|
||
" <th></th>\n",
|
||
" </tr>\n",
|
||
" </thead>\n",
|
||
" <tbody>\n",
|
||
" <tr>\n",
|
||
" <th>22159</th>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>8920</th>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>65507</th>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>43196</th>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>59745</th>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>...</th>\n",
|
||
" <td>...</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>66546</th>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>68798</th>\n",
|
||
" <td>1</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>61409</th>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>69259</th>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>17231</th>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" </tbody>\n",
|
||
"</table>\n",
|
||
"<p>4088 rows × 1 columns</p>\n",
|
||
"</div>"
|
||
],
|
||
"text/plain": [
|
||
" stroke\n",
|
||
"id \n",
|
||
"22159 0\n",
|
||
"8920 0\n",
|
||
"65507 0\n",
|
||
"43196 0\n",
|
||
"59745 0\n",
|
||
"... ...\n",
|
||
"66546 0\n",
|
||
"68798 1\n",
|
||
"61409 0\n",
|
||
"69259 0\n",
|
||
"17231 0\n",
|
||
"\n",
|
||
"[4088 rows x 1 columns]"
|
||
]
|
||
},
|
||
"metadata": {},
|
||
"output_type": "display_data"
|
||
},
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"'X_test'"
|
||
]
|
||
},
|
||
"metadata": {},
|
||
"output_type": "display_data"
|
||
},
|
||
{
|
||
"data": {
|
||
"text/html": [
|
||
"<div>\n",
|
||
"<style scoped>\n",
|
||
" .dataframe tbody tr th:only-of-type {\n",
|
||
" vertical-align: middle;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .dataframe tbody tr th {\n",
|
||
" vertical-align: top;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .dataframe thead th {\n",
|
||
" text-align: right;\n",
|
||
" }\n",
|
||
"</style>\n",
|
||
"<table border=\"1\" class=\"dataframe\">\n",
|
||
" <thead>\n",
|
||
" <tr style=\"text-align: right;\">\n",
|
||
" <th></th>\n",
|
||
" <th>gender</th>\n",
|
||
" <th>age</th>\n",
|
||
" <th>hypertension</th>\n",
|
||
" <th>heart_disease</th>\n",
|
||
" <th>ever_married</th>\n",
|
||
" <th>work_type</th>\n",
|
||
" <th>Residence_type</th>\n",
|
||
" <th>avg_glucose_level</th>\n",
|
||
" <th>bmi</th>\n",
|
||
" <th>smoking_status</th>\n",
|
||
" <th>stroke</th>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>id</th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" </tr>\n",
|
||
" </thead>\n",
|
||
" <tbody>\n",
|
||
" <tr>\n",
|
||
" <th>18072</th>\n",
|
||
" <td>Female</td>\n",
|
||
" <td>39.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>Yes</td>\n",
|
||
" <td>Govt_job</td>\n",
|
||
" <td>Urban</td>\n",
|
||
" <td>107.47</td>\n",
|
||
" <td>21.3</td>\n",
|
||
" <td>Unknown</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>67063</th>\n",
|
||
" <td>Male</td>\n",
|
||
" <td>62.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>Yes</td>\n",
|
||
" <td>Self-employed</td>\n",
|
||
" <td>Urban</td>\n",
|
||
" <td>130.56</td>\n",
|
||
" <td>36.1</td>\n",
|
||
" <td>Unknown</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>40387</th>\n",
|
||
" <td>Female</td>\n",
|
||
" <td>17.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>No</td>\n",
|
||
" <td>Private</td>\n",
|
||
" <td>Rural</td>\n",
|
||
" <td>77.46</td>\n",
|
||
" <td>24.0</td>\n",
|
||
" <td>Unknown</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>18032</th>\n",
|
||
" <td>Male</td>\n",
|
||
" <td>62.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>1</td>\n",
|
||
" <td>Yes</td>\n",
|
||
" <td>Private</td>\n",
|
||
" <td>Rural</td>\n",
|
||
" <td>90.61</td>\n",
|
||
" <td>25.8</td>\n",
|
||
" <td>smokes</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>5478</th>\n",
|
||
" <td>Female</td>\n",
|
||
" <td>60.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>Yes</td>\n",
|
||
" <td>Self-employed</td>\n",
|
||
" <td>Urban</td>\n",
|
||
" <td>203.04</td>\n",
|
||
" <td>NaN</td>\n",
|
||
" <td>smokes</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>...</th>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>57710</th>\n",
|
||
" <td>Female</td>\n",
|
||
" <td>50.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>Yes</td>\n",
|
||
" <td>Private</td>\n",
|
||
" <td>Rural</td>\n",
|
||
" <td>112.25</td>\n",
|
||
" <td>21.6</td>\n",
|
||
" <td>Unknown</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>63043</th>\n",
|
||
" <td>Female</td>\n",
|
||
" <td>27.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>No</td>\n",
|
||
" <td>Private</td>\n",
|
||
" <td>Urban</td>\n",
|
||
" <td>61.80</td>\n",
|
||
" <td>26.8</td>\n",
|
||
" <td>formerly smoked</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>63986</th>\n",
|
||
" <td>Male</td>\n",
|
||
" <td>60.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>Yes</td>\n",
|
||
" <td>Private</td>\n",
|
||
" <td>Rural</td>\n",
|
||
" <td>153.48</td>\n",
|
||
" <td>37.3</td>\n",
|
||
" <td>never smoked</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>28461</th>\n",
|
||
" <td>Male</td>\n",
|
||
" <td>15.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>No</td>\n",
|
||
" <td>Never_worked</td>\n",
|
||
" <td>Rural</td>\n",
|
||
" <td>79.59</td>\n",
|
||
" <td>28.4</td>\n",
|
||
" <td>Unknown</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>54975</th>\n",
|
||
" <td>Male</td>\n",
|
||
" <td>7.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>No</td>\n",
|
||
" <td>Self-employed</td>\n",
|
||
" <td>Rural</td>\n",
|
||
" <td>64.06</td>\n",
|
||
" <td>18.9</td>\n",
|
||
" <td>Unknown</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" </tbody>\n",
|
||
"</table>\n",
|
||
"<p>1022 rows × 11 columns</p>\n",
|
||
"</div>"
|
||
],
|
||
"text/plain": [
|
||
" gender age hypertension heart_disease ever_married work_type \\\n",
|
||
"id \n",
|
||
"18072 Female 39.0 0 0 Yes Govt_job \n",
|
||
"67063 Male 62.0 0 0 Yes Self-employed \n",
|
||
"40387 Female 17.0 0 0 No Private \n",
|
||
"18032 Male 62.0 0 1 Yes Private \n",
|
||
"5478 Female 60.0 0 0 Yes Self-employed \n",
|
||
"... ... ... ... ... ... ... \n",
|
||
"57710 Female 50.0 0 0 Yes Private \n",
|
||
"63043 Female 27.0 0 0 No Private \n",
|
||
"63986 Male 60.0 0 0 Yes Private \n",
|
||
"28461 Male 15.0 0 0 No Never_worked \n",
|
||
"54975 Male 7.0 0 0 No Self-employed \n",
|
||
"\n",
|
||
" Residence_type avg_glucose_level bmi smoking_status stroke \n",
|
||
"id \n",
|
||
"18072 Urban 107.47 21.3 Unknown 0 \n",
|
||
"67063 Urban 130.56 36.1 Unknown 0 \n",
|
||
"40387 Rural 77.46 24.0 Unknown 0 \n",
|
||
"18032 Rural 90.61 25.8 smokes 0 \n",
|
||
"5478 Urban 203.04 NaN smokes 0 \n",
|
||
"... ... ... ... ... ... \n",
|
||
"57710 Rural 112.25 21.6 Unknown 0 \n",
|
||
"63043 Urban 61.80 26.8 formerly smoked 0 \n",
|
||
"63986 Rural 153.48 37.3 never smoked 0 \n",
|
||
"28461 Rural 79.59 28.4 Unknown 0 \n",
|
||
"54975 Rural 64.06 18.9 Unknown 0 \n",
|
||
"\n",
|
||
"[1022 rows x 11 columns]"
|
||
]
|
||
},
|
||
"metadata": {},
|
||
"output_type": "display_data"
|
||
},
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"'y_test'"
|
||
]
|
||
},
|
||
"metadata": {},
|
||
"output_type": "display_data"
|
||
},
|
||
{
|
||
"data": {
|
||
"text/html": [
|
||
"<div>\n",
|
||
"<style scoped>\n",
|
||
" .dataframe tbody tr th:only-of-type {\n",
|
||
" vertical-align: middle;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .dataframe tbody tr th {\n",
|
||
" vertical-align: top;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .dataframe thead th {\n",
|
||
" text-align: right;\n",
|
||
" }\n",
|
||
"</style>\n",
|
||
"<table border=\"1\" class=\"dataframe\">\n",
|
||
" <thead>\n",
|
||
" <tr style=\"text-align: right;\">\n",
|
||
" <th></th>\n",
|
||
" <th>stroke</th>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>id</th>\n",
|
||
" <th></th>\n",
|
||
" </tr>\n",
|
||
" </thead>\n",
|
||
" <tbody>\n",
|
||
" <tr>\n",
|
||
" <th>18072</th>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>67063</th>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>40387</th>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>18032</th>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>5478</th>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>...</th>\n",
|
||
" <td>...</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>57710</th>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>63043</th>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>63986</th>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>28461</th>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>54975</th>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" </tbody>\n",
|
||
"</table>\n",
|
||
"<p>1022 rows × 1 columns</p>\n",
|
||
"</div>"
|
||
],
|
||
"text/plain": [
|
||
" stroke\n",
|
||
"id \n",
|
||
"18072 0\n",
|
||
"67063 0\n",
|
||
"40387 0\n",
|
||
"18032 0\n",
|
||
"5478 0\n",
|
||
"... ...\n",
|
||
"57710 0\n",
|
||
"63043 0\n",
|
||
"63986 0\n",
|
||
"28461 0\n",
|
||
"54975 0\n",
|
||
"\n",
|
||
"[1022 rows x 1 columns]"
|
||
]
|
||
},
|
||
"metadata": {},
|
||
"output_type": "display_data"
|
||
}
|
||
],
|
||
"source": [
|
||
"X_train, X_val, X_test, y_train, y_val, y_test = split_stratified_into_train_val_test(\n",
|
||
" df, stratify_colname=\"stroke\", frac_train=0.80, frac_val=0, frac_test=0.20, random_state=random_state\n",
|
||
")\n",
|
||
"\n",
|
||
"display(\"X_train\", X_train)\n",
|
||
"display(\"y_train\", y_train)\n",
|
||
"\n",
|
||
"display(\"X_test\", X_test)\n",
|
||
"display(\"y_test\", y_test)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"Выберем ориентир для задачи классификации. Для этого применим алгоритм случайного предсказания, т.е. в каждом случае в качестве предсказания выберем случайный класс."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 4,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Baseline Accuracy: 0.5\n",
|
||
"Baseline Precision: 0.05758157389635317\n",
|
||
"Baseline Recall: 0.6\n",
|
||
"Baseline F1 Score: 0.10507880910683012\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"import numpy as np\n",
|
||
"from sklearn.metrics import precision_score, recall_score, accuracy_score, f1_score\n",
|
||
"\n",
|
||
"# Получаем уникальные классы для целевого признака из тренировочного набора данных\n",
|
||
"unique_classes = np.unique(y_train)\n",
|
||
"\n",
|
||
"# Генерируем случайные предсказания, выбирая случайное значение из области значений целевого признака\n",
|
||
"random_predictions = np.random.choice(unique_classes, size=len(y_test))\n",
|
||
"\n",
|
||
"# Вычисление метрик для ориентира\n",
|
||
"baseline_accuracy = accuracy_score(y_test, random_predictions)\n",
|
||
"baseline_precision = precision_score(y_test, random_predictions)\n",
|
||
"baseline_recall = recall_score(y_test, random_predictions)\n",
|
||
"baseline_f1 = f1_score(y_test, random_predictions)\n",
|
||
"\n",
|
||
"print('Baseline Accuracy:', baseline_accuracy)\n",
|
||
"print('Baseline Precision:', baseline_precision)\n",
|
||
"print('Baseline Recall:', baseline_recall)\n",
|
||
"print('Baseline F1 Score:', baseline_f1)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"#### Метрики модели\n",
|
||
"- Accuracy: доля правильных предсказаний от общего числа примеров. Простая, но бесполезная метрика в задачах с дисбалансом классов — не учитывает, как модель работает с редким классом.\n",
|
||
"- Precision: доля правильных предсказаний положительного класса среди всех предсказанных положительных. Полезна, если критичны ложные срабатывания (например, чтобы не ошибаться с инсультом).\n",
|
||
"- Recall: доля найденных объектов положительного класса среди всех реальных примеров положительного класса. Помогает понять, насколько хорошо модель \"ловит\" положительный класс. Важна, чтобы минимизировать пропуски инсультов.\n",
|
||
"- F1 Score: гармоническое среднее между precision и recall. Учитывает и точность, и полноту, что важно в задачах с несбалансированными классами.\n",
|
||
"Эти метрики показывают разные аспекты работы модели: от общего уровня точности до способности находить редкие классы и балансировать между precision и recall. Это позволяет оценить модель всесторонне."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### Сформируем конвейер для классификации"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 5,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"from sklearn.compose import ColumnTransformer\n",
|
||
"from sklearn.discriminant_analysis import StandardScaler\n",
|
||
"from sklearn.impute import SimpleImputer\n",
|
||
"from sklearn.pipeline import Pipeline\n",
|
||
"from sklearn.preprocessing import OneHotEncoder\n",
|
||
"\n",
|
||
"columns_to_drop = [\"work_type\", \"stroke\"]\n",
|
||
"columns_not_to_modify = [\"hypertension\", \"heart_disease\"]\n",
|
||
"\n",
|
||
"num_columns = [\n",
|
||
" column\n",
|
||
" for column in df.columns\n",
|
||
" if column not in columns_to_drop\n",
|
||
" and column not in columns_not_to_modify\n",
|
||
" and df[column].dtype != \"object\"\n",
|
||
"]\n",
|
||
"\n",
|
||
"cat_columns = [\n",
|
||
" column\n",
|
||
" for column in df.columns\n",
|
||
" if column not in columns_to_drop\n",
|
||
" and column not in columns_not_to_modify\n",
|
||
" and df[column].dtype == \"object\"\n",
|
||
"]\n",
|
||
"\n",
|
||
"num_imputer = SimpleImputer(strategy=\"median\")\n",
|
||
"num_scaler = StandardScaler()\n",
|
||
"preprocessing_num = Pipeline(\n",
|
||
" [\n",
|
||
" (\"imputer\", num_imputer),\n",
|
||
" (\"scaler\", num_scaler),\n",
|
||
" ]\n",
|
||
")\n",
|
||
"\n",
|
||
"cat_imputer = SimpleImputer(strategy=\"constant\", fill_value=\"unknown\")\n",
|
||
"cat_encoder = OneHotEncoder(handle_unknown=\"ignore\", sparse_output=False, drop=\"first\")\n",
|
||
"preprocessing_cat = Pipeline(\n",
|
||
" [\n",
|
||
" (\"imputer\", cat_imputer),\n",
|
||
" (\"encoder\", cat_encoder),\n",
|
||
" ]\n",
|
||
")\n",
|
||
"\n",
|
||
"features_preprocessing = ColumnTransformer(\n",
|
||
" verbose_feature_names_out=False,\n",
|
||
" transformers=[\n",
|
||
" (\"prepocessing_num\", preprocessing_num, num_columns),\n",
|
||
" (\"prepocessing_cat\", preprocessing_cat, cat_columns),\n",
|
||
" ],\n",
|
||
" remainder=\"passthrough\"\n",
|
||
")\n",
|
||
"\n",
|
||
"drop_columns = ColumnTransformer(\n",
|
||
" verbose_feature_names_out=False,\n",
|
||
" transformers=[\n",
|
||
" (\"drop_columns\", \"drop\", columns_to_drop),\n",
|
||
" ],\n",
|
||
" remainder=\"passthrough\",\n",
|
||
")\n",
|
||
"\n",
|
||
"pipeline_end = Pipeline(\n",
|
||
" [\n",
|
||
" (\"features_preprocessing\", features_preprocessing),\n",
|
||
" (\"drop_columns\", drop_columns),\n",
|
||
" ]\n",
|
||
")"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"Теперь проверим работу конвейера:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 6,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/html": [
|
||
"<div>\n",
|
||
"<style scoped>\n",
|
||
" .dataframe tbody tr th:only-of-type {\n",
|
||
" vertical-align: middle;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .dataframe tbody tr th {\n",
|
||
" vertical-align: top;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .dataframe thead th {\n",
|
||
" text-align: right;\n",
|
||
" }\n",
|
||
"</style>\n",
|
||
"<table border=\"1\" class=\"dataframe\">\n",
|
||
" <thead>\n",
|
||
" <tr style=\"text-align: right;\">\n",
|
||
" <th></th>\n",
|
||
" <th>age</th>\n",
|
||
" <th>avg_glucose_level</th>\n",
|
||
" <th>bmi</th>\n",
|
||
" <th>gender_Male</th>\n",
|
||
" <th>gender_Other</th>\n",
|
||
" <th>ever_married_Yes</th>\n",
|
||
" <th>Residence_type_Urban</th>\n",
|
||
" <th>smoking_status_formerly smoked</th>\n",
|
||
" <th>smoking_status_never smoked</th>\n",
|
||
" <th>smoking_status_smokes</th>\n",
|
||
" <th>hypertension</th>\n",
|
||
" <th>heart_disease</th>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>id</th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" </tr>\n",
|
||
" </thead>\n",
|
||
" <tbody>\n",
|
||
" <tr>\n",
|
||
" <th>22159</th>\n",
|
||
" <td>0.472344</td>\n",
|
||
" <td>-0.194427</td>\n",
|
||
" <td>-0.059214</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>1</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>8920</th>\n",
|
||
" <td>0.339807</td>\n",
|
||
" <td>-0.653763</td>\n",
|
||
" <td>0.587887</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>65507</th>\n",
|
||
" <td>-0.455418</td>\n",
|
||
" <td>-1.111325</td>\n",
|
||
" <td>1.196162</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>43196</th>\n",
|
||
" <td>0.383986</td>\n",
|
||
" <td>-1.026600</td>\n",
|
||
" <td>1.713843</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>59745</th>\n",
|
||
" <td>-0.720492</td>\n",
|
||
" <td>-0.645113</td>\n",
|
||
" <td>3.228060</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>...</th>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>66546</th>\n",
|
||
" <td>-1.029746</td>\n",
|
||
" <td>-0.571034</td>\n",
|
||
" <td>-0.499243</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>68798</th>\n",
|
||
" <td>0.649060</td>\n",
|
||
" <td>-1.019502</td>\n",
|
||
" <td>-0.123924</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>61409</th>\n",
|
||
" <td>-0.499597</td>\n",
|
||
" <td>-1.055433</td>\n",
|
||
" <td>-0.098040</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>1</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>69259</th>\n",
|
||
" <td>1.488464</td>\n",
|
||
" <td>-0.110367</td>\n",
|
||
" <td>0.070206</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>17231</th>\n",
|
||
" <td>-0.853030</td>\n",
|
||
" <td>-0.341699</td>\n",
|
||
" <td>-0.602779</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" </tbody>\n",
|
||
"</table>\n",
|
||
"<p>4088 rows × 12 columns</p>\n",
|
||
"</div>"
|
||
],
|
||
"text/plain": [
|
||
" age avg_glucose_level bmi gender_Male gender_Other \\\n",
|
||
"id \n",
|
||
"22159 0.472344 -0.194427 -0.059214 0.0 0.0 \n",
|
||
"8920 0.339807 -0.653763 0.587887 0.0 0.0 \n",
|
||
"65507 -0.455418 -1.111325 1.196162 1.0 0.0 \n",
|
||
"43196 0.383986 -1.026600 1.713843 0.0 0.0 \n",
|
||
"59745 -0.720492 -0.645113 3.228060 0.0 0.0 \n",
|
||
"... ... ... ... ... ... \n",
|
||
"66546 -1.029746 -0.571034 -0.499243 0.0 0.0 \n",
|
||
"68798 0.649060 -1.019502 -0.123924 0.0 0.0 \n",
|
||
"61409 -0.499597 -1.055433 -0.098040 1.0 0.0 \n",
|
||
"69259 1.488464 -0.110367 0.070206 0.0 0.0 \n",
|
||
"17231 -0.853030 -0.341699 -0.602779 0.0 0.0 \n",
|
||
"\n",
|
||
" ever_married_Yes Residence_type_Urban smoking_status_formerly smoked \\\n",
|
||
"id \n",
|
||
"22159 0.0 1.0 1.0 \n",
|
||
"8920 1.0 0.0 1.0 \n",
|
||
"65507 1.0 0.0 0.0 \n",
|
||
"43196 1.0 1.0 0.0 \n",
|
||
"59745 1.0 1.0 0.0 \n",
|
||
"... ... ... ... \n",
|
||
"66546 0.0 1.0 0.0 \n",
|
||
"68798 1.0 0.0 1.0 \n",
|
||
"61409 0.0 1.0 1.0 \n",
|
||
"69259 1.0 0.0 0.0 \n",
|
||
"17231 0.0 1.0 0.0 \n",
|
||
"\n",
|
||
" smoking_status_never smoked smoking_status_smokes hypertension \\\n",
|
||
"id \n",
|
||
"22159 0.0 0.0 1 \n",
|
||
"8920 0.0 0.0 0 \n",
|
||
"65507 1.0 0.0 0 \n",
|
||
"43196 0.0 0.0 0 \n",
|
||
"59745 0.0 0.0 0 \n",
|
||
"... ... ... ... \n",
|
||
"66546 1.0 0.0 0 \n",
|
||
"68798 0.0 0.0 0 \n",
|
||
"61409 0.0 0.0 1 \n",
|
||
"69259 0.0 1.0 0 \n",
|
||
"17231 1.0 0.0 0 \n",
|
||
"\n",
|
||
" heart_disease \n",
|
||
"id \n",
|
||
"22159 0 \n",
|
||
"8920 0 \n",
|
||
"65507 0 \n",
|
||
"43196 0 \n",
|
||
"59745 0 \n",
|
||
"... ... \n",
|
||
"66546 0 \n",
|
||
"68798 0 \n",
|
||
"61409 0 \n",
|
||
"69259 0 \n",
|
||
"17231 0 \n",
|
||
"\n",
|
||
"[4088 rows x 12 columns]"
|
||
]
|
||
},
|
||
"execution_count": 6,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"preprocessing_result = pipeline_end.fit_transform(X_train)\n",
|
||
"preprocessed_df = pd.DataFrame(\n",
|
||
" preprocessing_result,\n",
|
||
" columns=pipeline_end.get_feature_names_out(),\n",
|
||
")\n",
|
||
"\n",
|
||
"preprocessed_df"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"Подберем оптимальные гиперпараметры для каждой из выбранных моделей методом поиска по сетке и сформируем их набор.\n",
|
||
"\n",
|
||
"knn -- k-ближайших соседей\n",
|
||
"\n",
|
||
"random_forest -- метод случайного леса (набор деревьев решений)\n",
|
||
"\n",
|
||
"mlp -- многослойный персептрон (нейронная сеть)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 7,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"d:\\code\\mai\\labs\\AIM-PIbd-31-Bakalskaya-E-D\\lab_4\\venv\\Lib\\site-packages\\numpy\\ma\\core.py:2881: RuntimeWarning: invalid value encountered in cast\n",
|
||
" _data = np.array(data, dtype=dtype, copy=copy,\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Лучшие параметры для knn: {'n_neighbors': 1, 'weights': 'uniform'}\n",
|
||
"Лучшие параметры для random_forest: {'class_weight': 'balanced_subsample', 'criterion': 'entropy', 'max_depth': 7, 'max_features': 'sqrt', 'n_estimators': 50, 'random_state': 9}\n",
|
||
"Лучшие параметры для mlp: {'alpha': np.float64(0.1), 'early_stopping': True, 'hidden_layer_sizes': np.int64(14), 'max_iter': 1000, 'random_state': 9, 'solver': 'adam'}\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"from sklearn.model_selection import GridSearchCV\n",
|
||
"from sklearn import neighbors, ensemble, neural_network\n",
|
||
"\n",
|
||
"# Словарь с вариантами гиперпараметров для каждой модели\n",
|
||
"param_grids = {\n",
|
||
" \"knn\": {\n",
|
||
" \"n_neighbors\": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30], \n",
|
||
" \"weights\": ['uniform', 'distance']\n",
|
||
" },\n",
|
||
" \"random_forest\": {\n",
|
||
" \"n_estimators\": [10, 20, 30, 40, 50, 100, 150, 200, 250, 500],\n",
|
||
" \"max_features\": [\"sqrt\", \"log2\", 2],\n",
|
||
" \"max_depth\": [2, 3, 4, 5, 6, 7, 8, 9, 10],\n",
|
||
" \"criterion\": [\"gini\", \"entropy\", \"log_loss\"],\n",
|
||
" \"random_state\": [random_state],\n",
|
||
" \"class_weight\": [\"balanced\", \"balanced_subsample\"]\n",
|
||
" },\n",
|
||
" \"mlp\": {\n",
|
||
" \"solver\": ['adam'], \n",
|
||
" \"max_iter\": [1000, 1100, 1200, 1300, 1400, 1500, 1600, 1700, 1800, 1900, 2000], \n",
|
||
" \"alpha\": 10.0 ** -np.arange(1, 10), \n",
|
||
" \"hidden_layer_sizes\":np.arange(10, 15), \n",
|
||
" \"early_stopping\": [True, False],\n",
|
||
" \"random_state\": [random_state]\n",
|
||
" }\n",
|
||
"}\n",
|
||
"\n",
|
||
"# Создаем экземпляры моделей\n",
|
||
"models = {\n",
|
||
" \"knn\": neighbors.KNeighborsClassifier(),\n",
|
||
" \"random_forest\": ensemble.RandomForestClassifier(),\n",
|
||
" \"mlp\": neural_network.MLPClassifier()\n",
|
||
"}\n",
|
||
"\n",
|
||
"# Словарь для хранения моделей с их лучшими параметрами\n",
|
||
"class_models = {}\n",
|
||
"\n",
|
||
"# Выполнение поиска по сетке для каждой модели\n",
|
||
"for model_name, model in models.items():\n",
|
||
" # Создаем GridSearchCV для текущей модели\n",
|
||
" gs_optimizer = GridSearchCV(estimator=model, param_grid=param_grids[model_name], scoring=\"f1\", n_jobs=-1)\n",
|
||
" \n",
|
||
" # Обучаем GridSearchCV\n",
|
||
" gs_optimizer.fit(preprocessed_df, y_train.values.ravel())\n",
|
||
" \n",
|
||
" # Получаем лучшие параметры\n",
|
||
" best_params = gs_optimizer.best_params_\n",
|
||
" print(f\"Лучшие параметры для {model_name}: {best_params}\")\n",
|
||
" \n",
|
||
" class_models[model_name] = {\n",
|
||
" \"model\": model.set_params(**best_params) # Настраиваем модель с лучшими параметрами\n",
|
||
" }"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"#### ЖЕСТЬ ЭТА ХРЕНЬ 12 МИНУТ СОЗДАВАЛАСЬ..."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"что ж теперь... обучим модели разными способами модели и посмотрим на качество обучения"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 8,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Model: knn\n",
|
||
"Model: random_forest\n",
|
||
"Model: mlp\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"from sklearn.metrics import confusion_matrix\n",
|
||
"\n",
|
||
"for model_name in class_models.keys():\n",
|
||
" print(f\"Model: {model_name}\")\n",
|
||
" model = class_models[model_name][\"model\"]\n",
|
||
"\n",
|
||
" model_pipeline = Pipeline([(\"pipeline\", pipeline_end), (\"model\", model)])\n",
|
||
" model_pipeline = model_pipeline.fit(X_train, y_train.values.ravel())\n",
|
||
"\n",
|
||
" y_train_predict = model_pipeline.predict(X_train)\n",
|
||
" y_test_probs = model_pipeline.predict_proba(X_test)[:, 1]\n",
|
||
" y_test_predict = np.where(y_test_probs > 0.5, 1, 0)\n",
|
||
"\n",
|
||
" class_models[model_name][\"pipeline\"] = model_pipeline\n",
|
||
" class_models[model_name][\"probs\"] = y_test_probs\n",
|
||
" class_models[model_name][\"preds\"] = y_test_predict\n",
|
||
"\n",
|
||
" class_models[model_name][\"Precision_train\"] = precision_score(\n",
|
||
" y_train, y_train_predict\n",
|
||
" )\n",
|
||
" class_models[model_name][\"Precision_test\"] = precision_score(\n",
|
||
" y_test, y_test_predict\n",
|
||
" )\n",
|
||
" class_models[model_name][\"Recall_train\"] = recall_score(\n",
|
||
" y_train, y_train_predict\n",
|
||
" )\n",
|
||
" class_models[model_name][\"Recall_test\"] = recall_score(\n",
|
||
" y_test, y_test_predict\n",
|
||
" )\n",
|
||
" class_models[model_name][\"Accuracy_train\"] = accuracy_score(\n",
|
||
" y_train, y_train_predict\n",
|
||
" )\n",
|
||
" class_models[model_name][\"Accuracy_test\"] = accuracy_score(\n",
|
||
" y_test, y_test_predict\n",
|
||
" ) \n",
|
||
" class_models[model_name][\"F1_train\"] = f1_score(y_train, y_train_predict)\n",
|
||
" class_models[model_name][\"F1_test\"] = f1_score(y_test, y_test_predict)\n",
|
||
" class_models[model_name][\"Confusion_matrix\"] = confusion_matrix(\n",
|
||
" y_test, y_test_predict\n",
|
||
" )"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"Матрицы неточностей:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 9,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"image/png": "iVBORw0KGgoAAAANSUhEUgAABBIAAANrCAYAAAD70rtBAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAAC8qklEQVR4nOzdfXzN9f/H8efZ9Ww7G2IzZsjlihQ1QynGSKX4VWrlIvFNVBSVvrloyqILIhddyMU36qsLvkIKhTCSUkKuQ9gUZi7a1Tmf3x9y6pwNZ2ezq8/jfrt9brfO+/N+f87r7Hu+28vr836/PxbDMAwBAAAAAAC4waukAwAAAAAAAGUHhQQAAAAAAOA2CgkAAAAAAMBtFBIAAAAAAIDbKCQAAAAAAAC3UUgAAAAAAABuo5AAAAAAAADcRiEBAAAAAAC4jUICAAAAAABwG4UEAJKkUaNGyWKx6I8//ijpUAAAQDGyWCwaNWpUSYdxQf/5z3/UsGFD+fr6KiwsrKTDASAKCQAAAABKqV9++UW9evXSlVdeqXfeeUdvv/12SYeUx+HDhzVq1Cht3ry5pEMBio1PSQcAAAAAAPlZuXKl7Ha73njjDdWtW7ekw8nX4cOH9cILL6hWrVpq2rRpSYcDFAtmJAAAAAClyJkzZ0o6hFLj6NGjklSkSxrOnj1bZNcCzIpCAoAL2r9/v+rWraurr75aaWlpuvnmm3X11Vdr27ZtuuWWW1ShQgVVr15d48aNcxq3cuVKWSwWzZs3Ty+99JJq1KihgIAAtWvXTrt37y6hTwMAQOlzfo+ibdu26f7771fFihXVunVr/fTTT+rVq5fq1KmjgIAARURE6KGHHtKxY8fyHb9792716tVLYWFhCg0NVe/evfP8gzkrK0uDBw9WlSpVFBISojvuuEO//fZbvnH98MMP6tSpk6xWq4KDg9WuXTutX7/eqc/MmTNlsVi0Zs0aPf7446pSpYrCwsL0r3/9S9nZ2UpPT1ePHj1UsWJFVaxYUU8//bQMw3D7Z1OrVi2NHDlSklSlSpU8ezlMmTJFV111lfz9/RUZGakBAwYoPT3d6Rrnc5dNmzbppptuUoUKFfTcc885fh4jR45U3bp15e/vr6ioKD399NPKyspyusayZcvUunVrhYWFKTg4WA0aNHBcY+XKlbr++uslSb1795bFYpHFYtHMmTPd/pxAWcTSBgD52rNnj9q2batKlSpp2bJluuKKKyRJJ06cUMeOHdW1a1fdc889+vjjj/XMM8+ocePG6tSpk9M1Xn75ZXl5eWnIkCE6efKkxo0bp8TERG3YsKEkPhIAAKXW3XffrXr16mnMmDEyDEPLli3T3r171bt3b0VERGjr1q16++23tXXrVq1fv14Wi8Vp/D333KPatWsrOTlZ33//vd59911VrVpVY8eOdfR5+OGH9f777+v+++9Xy5Yt9dVXX6lz5855Ytm6datuvPFGWa1WPf300/L19dVbb72lm2++WatWrVJsbKxT/8cee0wRERF64YUXtH79er399tsKCwvTunXrVLNmTY0ZM0ZLlizRK6+8oquvvlo9evRw62cyYcIEzZ49W/Pnz9fUqVMVHBysJk2aSDpXQHnhhRcUHx+v/v37a8eOHZo6dao2btyotWvXytfX13GdY8eOqVOnTurevbseeOABhYeHy26364477tCaNWvUr18/NWrUSFu2bNH48eO1c+dOLViwwPGzuO2229SkSRMlJSXJ399fu3fv1tq1ayVJjRo1UlJSkkaMGKF+/frpxhtvlCS1bNnSrc8IlFkGABiGMXLkSEOS8fvvvxvbt283IiMjjeuvv944fvy4o0+bNm0MScbs2bMdbVlZWUZERITRrVs3R9vXX39tSDIaNWpkZGVlOdrfeOMNQ5KxZcuW4vlQAACUcuf//t53331O7WfPns3T94MPPjAkGatXr84z/qGHHnLqe9dddxmVK1d2vN68ebMhyXj00Ued+t1///2GJGPkyJGOtjvvvNPw8/Mz9uzZ42g7fPiwERISYtx0002OthkzZhiSjISEBMNutzva4+LiDIvFYjzyyCOOttzcXKNGjRpGmzZtLvETcfbP/OS8o0ePGn5+fkaHDh0Mm83maH/zzTcNScZ7773naDufu0ybNs3puv/5z38MLy8v45tvvnFqnzZtmiHJWLt2rWEYhjF+/Pg87+9q48aNhiRjxowZBfpsQFnG0gYATn7++We1adNGtWrV0vLly1WxYkWn88HBwXrggQccr/38/HTDDTdo7969ea7Vu3dv+fn5OV6fr9Ln1xcAADN75JFHnF4HBgY6/jszM1N//PGHWrRoIUn6/vvvLzn+xhtv1LFjx5SRkSFJWrJkiSTp8ccfd+o3aNAgp9c2m01ffvml7rzz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cKESEhJ09913a9WqVapevboeffRR9e3bV5K0b98+paamKj4+3jEmNDRUsbGxSklJUffu3ZWSkqKwsDBHEUE6t6Gxl5eXNmzYoLvuuuuScZeqQkLjxo2VmJioiRMnOrU/9dRTuv766zV69Gjde++9SklJ0ZtvvqkpU6Y4+tSqVUurV69W9+7d5e/vryuuuCLP9WfOnCmbzabY2FhVqFBB77//vgIDAxUdHe32NSSpXr166tKli/r27au33npLISEhevbZZ1W9enVH1ec8b29vzZkzR/fdd5/atm2rlStXKiIiQkOGDNHgwYNlt9vVunVrnTx5UmvXrpXValXPnj0L+6M0rTZ3pKvNHen5nouIytYXhze7dZ1hU/YXXVCAi2d7/D3t+Y9Ufz3z4DUlGA1QNpEzkDMUVoVgu/onHVL/pEMX7NPh3uMXfQT0NS1Pu51bAPn5aWuEOnTrcdE+X3xVT198Ve+C53NyvPXmu7F6812KB2XZwYMHnZaiXWjW2d69ezV16lQ9+eSTeu6557Rx40Y9/vjj8vPzU8+ePZWaem6z1/DwcKdx4eHhjnOpqamqWrWq03kfHx9VqlTJ0edSSt1CzqSkpDzPXL7uuus0b948ffjhh7r66qs1YsQIJSUlOU1nTEpK0q+//qorr7xSVarkP40nLCxM77zzjlq1aqUmTZpo+fLl+uyzz1S5cmW3r3HejBkz1KxZM912222Ki4uTYRhasmRJvtMdfXx89MEHH+iqq65S27ZtdfToUY0ePVrDhw9XcnKyGjVqpI4dO2rx4sVO01IAACXD42dBF2JqIwqOnIGcAQBKg6LIG1z3trlQIcFut+u6667TmDFjdO2116pfv37q27evpk2bVpwfWRbDKOiWMigNMjIyFBoaqhM768gaUurqQTCRWxveVNIhwMRyjWytyHhfJ0+eLJIN5c7/bu20tK98gzzb7DLnTLY+7/hOkcUEFBY5A0qLDt2YQYOSlZubqVXfvlSm84bo6Gi1b99e7777rqNt6tSpevHFF3Xo0CHt3btXV155pX744Qc1bdrU0adNmzZq2rSp3njjDb333nt66qmndOLE30+oyc3NVUBAgD766CO3ljbw1wQAABfMSAAAAO4qzryhVatW2rFjh1Pbzp07HUvvateurYiICK1YscJxPiMjQxs2bHA8RjguLk7p6enatGmTo89X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XS/P/qmEo0d5dfyoj/bvDHBqO7jLX1WrZ5dQRHB1/s6CpwfKPnIGcxvw0m+KbZ+hp//vSv1x5OLLHn/5/tzTdiJrZV20H1AQfAfLFjPmDaaZkXBeQECA2rdvr/bt22v48OF6+OGHNXLkSPXq1euCY4KC8t/l/1KqVKmiyMhIffDBB3rooYdktVolSadPn5a3t7c2bdrkNB1SOjedMj/+/v55plbi0javD1P/251nGwwes1O/7a2gj96toYwTvvr8v8673E797Hu983IdbWCpAy6TbRuDFHWl8x/76nWydPQQe3QApQk5gxkZGvDSIbXseFJD/6+uWxvhXnl1piTp+FE2vkNR4DuIssFUMxLyExMTozNnzj2H1dfXVzab7RIjpEaNGungwYNOFf5t27YpPT1dMTExjrbAwEAtWrRIAQEBSkhI0KlTpyRJ1157rWw2m44ePaq6des6Ha5TJFE4f57x0f5dQU5H5p/eykg/137iD7885yXp98P+SjsUcImrA5759O0qanjdGXV/LE2RtbJ0y10ndOsDx7VwxhUlHRrOMwp5oFwiZyj/Bo45pLZdT+jlAdH687SXKlbJUcUqOfILOLeRXbXoLN0/KE11G59VeI1stehwUkPfOKCfUoK0b3vgJa4OXBrfwTLKhHmDaWYkHDt2THfffbceeughNWnSRCEhIfruu+80btw4denSRZJUq1YtrVixQq1atZK/v78qVsy7w78kxcfHq3HjxkpMTNSECROUm5urRx99VG3atFHz5s2d+gYFBWnx4sXq1KmTOnXqpKVLl6p+/fpKTExUjx499Nprr+naa6/V77//rhUrVqhJkybq3LnzZf95ACg5O3+soKQ+tdV72BElDk5T6kE/TRsRqa/n5/87B8XPjJsm4W/kDOZ1e69zT9B59VPnZSOvDorSsnmVlJtj0bU3ntJdD/+ugAp2/X7YV2uWhOqDCeElES7KIb6DZZMZ8wbTFBKCg4MVGxur8ePHa8+ePcrJyVFUVJT69u2r5557TpL02muv6cknn9Q777yj6tWr69dff833WhaLRf/73//02GOP6aabbpKXl5c6duyoSZMmXfC9P//8cyUkJKhz585asmSJZsyYoRdffFFPPfWUDh06pCuuuEItWrTQbbfddrl+BPjLsz2aXPT8rQ1vLKZIYGYbllu1Ybm1pMPAhZhw0yT8jZzBvBIir7no+d8P+2lot7oX7QMUBt/BMsqEeYPFMMpo5CaXkZGh0NBQtbM+IB8L66pRcmw8VgwlKNfI0Ur9TydPnnSsKS+M879bW9yaJB9fz5Y35eZkav2SEUUWE1BY57/XN6uLfCysoQZgXuQNRcc0MxIAAHCXGacoAgAAz5gxbzD9ZosAAORhwk2TAACAh4oxb0hOTtb111+vkJAQVa1aVXfeead27Njh1CczM1MDBgxQ5cqVFRwcrG7duiktLc2pz4EDB9S5c2dVqFBBVatW1dChQ5Wbm+t2HBQSAABwYcbnQQMAAM8UZ96watUqDRgwQOvXr9eyZcuUk5OjDh06OJ4qJEmDBw/WZ599po8++kirVq3S4cOH1bVrV8d5m82mzp07Kzs7W+vWrdOsWbM0c+ZMjRgxwu04WNoAAIAru3Hu8HQsAAAwj2LMG5YuXer0eubMmapatao2bdqkm266SSdPntT06dM1d+5ctW3bVpI0Y8YMNWrUSOvXr1eLFi305Zdfatu2bVq+fLnCw8PVtGlTjR49Ws8884xGjRolP79L78HHjAQAAAAAAEpQRkaG05GVleXWuJMnT0qSKlWqJEnatGmTcnJyFB8f7+jTsGFD1axZUykpKZKklJQUNW7cWOHhfz82NCEhQRkZGdq6datb70shAQAAVyZc6wgAADxUBHlDVFSUQkNDHUdycvIl39Zut2vQoEFq1aqVrr76aklSamqq/Pz8FBYW5tQ3PDxcqampjj7/LCKcP3/+nDtY2gAAgAuLCrH7cgH7n1/reP311ys3N1fPPfecOnTooG3btikoKEjSubWOixcv1kcffaTQ0FANHDhQXbt21dq1ayX9vdYxIiJC69at05EjR9SjRw/5+vpqzJgxnn0QAADglqLIGw4ePOj0+Ed/f/9Ljh0wYIB+/vlnrVmzxrM3LwQKCQAAuDKMc4enYwugtKx1BAAAHiqCvMFqtToVEi5l4MCBWrRokVavXq0aNWo42iMiIpSdna309HSnWQlpaWmKiIhw9Pn222+drnd+puP5PpfC0gYAAC6DsrbWEQAAlH6GYWjgwIGaP3++vvrqK9WuXdvpfLNmzeTr66sVK1Y42nbs2KEDBw4oLi5OkhQXF6ctW7bo6NGjjj7Lli2T1WpVTEyMW3FQSAAAwEVRPMaprK11BAAAninOxz8OGDBA77//vubOnauQkBClpqYqNTVVf/75pyQpNDRUffr00ZNPPqmvv/5amzZtUu/evRUXF6cWLVpIkjp06KCYmBg9+OCD+vHHH/XFF1/o+eef14ABA9xaUiGxtAEAgLw82DTRaazK3lpHAADgoSLIG9w1depUSdLNN9/s1D5jxgz16tVLkjR+/Hh5eXmpW7duysrKUkJCgqZMmeLo6+3trUWLFql///6Ki4tTUFCQevbsqaSkJLfjoJAAAIALi2HI4uFaR0sZXesIAAA8UxR5g7sMN/oHBARo8uTJmjx58gX7REdHa8mSJQV6739iaQMAACWotKx1BAAAcBczEgAAcGX/6/B0bAEMGDBAc+fO1f/+9z/HWkfp3BrHwMBAp7WOlSpVktVq1WOPPXbBtY7jxo1Tampqgdc6AgAADxVj3lBaUEgAAMBFcU5RLC1rHQEAgGeKM28oLSgkAADgqhg3TSotax0BAICHijFvKC0oJAAA4Mowzh2ejgUAAOZhwryBzRYBAAAAAIDbmJEAAIALi3Hu8HQsAAAwDzPmDRQSAABwZcIpigAAwEMmzBsoJAAA4MJiP3d4OhYAAJiHGfMG9kgAAAAAAABuY0YCAACuTDhFEQAAeMiEeQOFBAAAXJnwedAAAMBDJswbKCQAAODCYhiyeHiHwNNxAACgbDJj3sAeCQAAAAAAwG3MSAAAwJUJ1zoCAAAPmTBvoJAAAIArQ5Knj2Mqm/kAAADwlAnzBgoJAAC4MONaRwAA4Bkz5g3skQAAAAAAANzGjAQAAFwZKsRaxyKNBAAAlHYmzBsoJAAA4MqEmyYBAAAPmTBvoJAAAIAruyRLIcYCAADzMGHeQCEBAAAXZtw0CQAAeMaMeQObLQIAAAAAALcxIwEAAFcmXOsIAAA8ZMK8gUICAACuTJgQAAAAD5kwb6CQAACAKxMmBAAAwEMmzBvYIwEAAAAAALiNGQkAALgy4WOcAACAh0yYN1BIAADAhRkf4wQAADxjxryBQgIAAK5MuNYRAAB4yIR5A3skAAAAAAAAt1FIAADAld0o3AEAAMyjGPOG1atX6/bbb1dkZKQsFosWLFjgdN4wDI0YMULVqlVTYGCg4uPjtWvXLqc+x48fV2JioqxWq8LCwtSnTx+dPn26QHFQSAAAwNX5KYqeHgAAwDyKMW84c+aMrrnmGk2ePDnf8+PGjdPEiRM1bdo0bdiwQUFBQUpISFBmZqajT2JiorZu3aply5Zp0aJFWr16tfr161egONgjAQCAPApTEKCQAACAuRRf3tCpUyd16tQp/ysZhiZMmKDnn39eXbp0kSTNnj1b4eHhWrBggbp3767t27dr6dKl2rhxo5o3by5JmjRpkm699Va9+uqrioyMdCsOZiQAAOCKGQkAAMBdRZA3ZGRkOB1ZWVkFDmPfvn1KTU1VfHy8oy00NFSxsbFKSUmRJKWkpCgsLMxRRJCk+Ph4eXl5acOGDW6/F4UEAAAAAABKUFRUlEJDQx1HcnJyga+RmpoqSQoPD3dqDw8Pd5xLTU1V1apVnc77+PioUqVKjj7uYGkDAACu7IY8XqLAZosAAJhLEeQNBw8elNVqdTT7+/sXQWCXD4UEAABcGfZzh6djAQCAeRRB3mC1Wp0KCZ6IiIiQJKWlpalatWqO9rS0NDVt2tTR5+jRo07jcnNzdfz4ccd4d7C0AQAAV+yRAAAA3FVK8obatWsrIiJCK1ascLRlZGRow4YNiouLkyTFxcUpPT1dmzZtcvT56quvZLfbFRsb6/Z7MSMBAAAAAIAy4PTp09q9e7fj9b59+7R582ZVqlRJNWvW1KBBg/Tiiy+qXr16ql27toYPH67IyEjdeeedkqRGjRqpY8eO6tu3r6ZNm6acnBwNHDhQ3bt3d/uJDRKFBAAA8mKPBAAA4K5izBu+++473XLLLY7XTz75pCSpZ8+emjlzpp5++mmdOXNG/fr1U3p6ulq3bq2lS5cqICDAMWbOnDkaOHCg2rVrJy8vL3Xr1k0TJ04sUBwUEgAAcFWYqYYsbQAAwFyKMW+4+eabZVxkjMViUVJSkpKSki7Yp1KlSpo7d26B3tcVhQQAAFwZKkRCUKSRAACA0s6EeQObLQIAAAAAALcxIwEAAFcsbQAAAO4yYd5AIQEAAFd2uyQPnwdt93AcAAAom0yYN1BIAADAlQnvLAAAAA+ZMG+gkAAAgCsTJgQAAMBDJswb2GwRAAAAAAC4jRkJAAC4shvy+HlM9rJ5ZwEAAHjIhHkDhQQAAFwYhl2G4dnmR56OAwAAZZMZ8wYKCQAAuDIMz+8QlNG1jgAAwEMmzBvYIwEAAAAAALiNGQkAALgyCrHWsYzeWQAAAB4yYd5AIQEAAFd2u2TxcM1iGV3rCAAAPGTCvIFCAgAArkx4ZwEAAHjIhHkDeyQAAAAAAAC3MSMBAAAXht0uw8MpimX1MU4AAMAzZswbKCQAAODKhFMUAQCAh0yYN1BIAADAld2QLOZKCAAAgIdMmDdQSAAAwJVhSPJ09+WymRAAAAAPmTBvoJBQRhl/feFyjewSjgRmZzNySjoEmFiuzn3/jDL6RxgoDo6cQTkez7wFgPKAvKHoUEgoo06dOiVJWnVqXglHAgAl79SpUwoNDS2y6xl2Q4aHUxRJTlDanM8Z1mhJCUcCAKUDeUPhUUgooyIjI3Xw4EGFhITIYrGUdDhlUkZGhqKionTw4EFZrdaSDgcmxHew8AzD0KlTpxQZGVnEF7bL8ymKZXP3ZZRf5AyFx+9rlAZ8DwuPvKHoUEgoo7y8vFSjRo2SDqNcsFqt/DJGieI7WDhFeUfhPDPeWUD5Rc5QdPh9jdKA72HhkDcUDa+SDgAAAAAAAJQdzEgAAMBFrpHl8VTD8xs5AQAAczBj3kAhAabl7++vkSNHyt/fv6RDgUnxHSx9/Pz8FBERoTWphduULiIiQn5+fkUUFYCSxu9rlAZ8D0sfM+cNFqOsLsoAAOAyyMzMVHZ24R6t6+fnp4CAgCKKCAAAlFZmzRsoJAAAAAAAALex2SIAAAAAAHAbhQQAAAAAAOA2CgkAAAAAAMBtFBKAIjRz5kyFhYWVdBgoJ0aNGqWmTZuWdBgAgMuEvAFFibwBxYlCAopdr169ZLFY9PLLLzu1L1iwQBaLpUDXqlWrliZMmFCoeIriGjCP33//Xf3791fNmjXl7++viIgIJSQkaO3atZIki8WiBQsWlGyQAFCOkDegLCNvQHlFIQElIiAgQGPHjtWJEydKOhS32Gw22e32kg4DpUC3bt30ww8/aNasWdq5c6cWLlyom2++WceOHXP7GoV9RBAAmA15A8oq8gaUVxQSUCLi4+MVERGh5OTki/b75JNPdNVVV8nf31+1atXSa6+95jh38803a//+/Ro8eLAsFssF70oYhqFRo0Y5KsGRkZF6/PHHL3qN81MNFy5cqJiYGPn7++vAgQM6ceKEevTooYoVK6pChQrq1KmTdu3adcH4f//9dzVv3lx33XWXsrKyZLfblZycrNq1ayswMFDXXHONPv7444L++FBC0tPT9c0332js2LG65ZZbFB0drRtuuEHDhg3THXfcoVq1akmS7rrrLlksFsfr81MN3333XdWuXdvxnOADBw6oS5cuCg4OltVq1T333KO0tLQLvv+ePXtUp04dDRw4UIZhKCsrS0OGDFH16tUVFBSk2NhYrVy58jL/FACg+JE3kDeUReQNKM8oJKBEeHt7a8yYMZo0aZJ+++23fPts2rRJ99xzj7p3764tW7Zo1KhRGj58uGbOnClJ+vTTT1WjRg0lJSXpyJEjOnLkSL7X+eSTTzR+/Hi99dZb2rVrlxYsWKDGjRtf8hpnz57V2LFj9e6772rr1q2qWrWqevXqpe+++04LFy5USkqKDMPQrbfeqpycnDzve/DgQd144426+uqr9fHHH8vf31/JycmaPXu2pk2bpq1bt2rw4MF64IEHtGrVqkL+RFEcgoODFRwcrAULFigrKyvP+Y0bN0qSZsyYoSNHjjheS9Lu3bv1ySef6NNPP9XmzZtlt9vVpUsXHT9+XKtWrdKyZcu0d+9e3Xvvvfm+908//aTWrVvr/vvv15tvvimLxaKBAwcqJSVFH374oX766Sfdfffd6tix40WTVAAoi8gbyBvKIvIGlGsGUMx69uxpdOnSxTAMw2jRooXx0EMPGYZhGPPnzzf++ZW8//77jfbt2zuNHTp0qBETE+N4HR0dbYwfP/6i7/faa68Z9evXN7Kzs/M9n981ZsyYYUgyNm/e7GjbuXOnIclYu3ato+2PP/4wAgMDjXnz5jnGhYaGGr/88osRFRVlPP7444bdbjcMwzAyMzONChUqGOvWrXN6rz59+hj33XffRT8DSo+PP/7YqFixohEQEGC0bNnSGDZsmPHjjz86zksy5s+f7zRm5MiRhq+vr3H06FFH25dffml4e3sbBw4ccLRt3brVkGR8++23jnHXXHONsXbtWqNixYrGq6++6ui7f/9+w9vb2zh06JDTe7Vr184YNmxYUX5kAChR5A3kDWUZeQPKK2YkoESNHTtWs2bN0vbt2/Oc2759u1q1auXU1qpVK+3atUs2m83t97j77rv1559/qk6dOurbt6/mz5+v3NzcS47z8/NTkyZNnOLx8fFRbGyso61y5cpq0KCBU/x//vmnbrzxRnXt2lVvvPGGY9rj7t27dfbsWbVv395RoQ4ODtbs2bO1Z88etz8PSla3bt10+PBhLVy4UB07dtTKlSt13XXXOe54XUh0dLSqVKnieL19+3ZFRUUpKirK0RYTE6OwsDCn79OBAwfUvn17jRgxQk899ZSjfcuWLbLZbKpfv77T92nVqlV8nwCUW+QN5A1lDXkDyisKCShRN910kxISEjRs2LDL9h5RUVHasWOHpkyZosDAQD366KO66aab8p1W+E+BgYEF3g1akvz9/RUfH69Fixbp0KFDjvbTp09LkhYvXqzNmzc7jm3btrHesYwJCAhQ+/btNXz4cK1bt069evXSyJEjLzomKCjIo/eqUqWKbrjhBn3wwQfKyMhwtJ8+fVre3t7atGmT0/dp+/bteuONNzx6LwAo7cgbyBvKIvIGlEcUElDiXn75ZX322WdKSUlxam/UqJHj0TjnrV27VvXr15e3t7ekc9V/d+4yBAYG6vbbb9fEiRO1cuVKpaSkaMuWLQW6RqNGjZSbm6sNGzY42o4dO6YdO3YoJibG0ebl5aX//Oc/atasmW655RYdPnxYkpw2X6pbt67T8c/qMsqemJgYnTlzRpLk6+vr9vfp4MGDOnjwoKNt27ZtSk9Pd/o+BQYGatGiRQoICFBCQoJOnTolSbr22mtls9l09OjRPN+niIiIIv6EAFB6kDeQN5R15A0oDygkoMQ1btxYiYmJmjhxolP7U089pRUrVmj06NHauXOnZs2apTfffFNDhgxx9KlVq5ZWr16tQ4cO6Y8//sj3+jNnztT06dP1888/a+/evXr//fcVGBio6Ohot68hSfXq1VOXLl3Ut29frVmzRj/++KMeeOABVa9eXV26dHHq6+3trTlz5uiaa65R27ZtlZqaqpCQEA0ZMkSDBw/WrFmztGfPHn3//feaNGmSZs2a5emPD8Xo2LFjatu2rd5//3399NNP2rdvnz766CONGzfO8R2oVauWVqxYodTU1Is+piw+Pt7x3f/+++/17bffqkePHmrTpo2aN2/u1DcoKEiLFy+Wj4+POnXqpNOnT6t+/fpKTExUjx499Omnn2rfvn369ttvlZycrMWLF1/WnwMAlCTyBvKGsoK8AeVaSW/SAPP556ZJ5+3bt8/w8/MzXL+SH3/8sRETE2P4+voaNWvWNF555RWn8ykpKUaTJk0Mf3//PGPPmz9/vhEbG2tYrVYjKCjIaNGihbF8+fKLXuP85keujh8/bjz44INGaGioERgYaCQkJBg7d+50nHcdl5OTY3Tt2tVo1KiRkZaWZtjtdmPChAlGgwYNDF9fX6NKlSpGQkKCsWrVKnd+dChhmZmZxrPPPmtcd911RmhoqFGhQgWjQYMGxvPPP2+cPXvWMAzDWLhwoVG3bl3Dx8fHiI6ONgzj782PXO3fv9+44447jKCgICMkJMS4++67jdTUVMd513GnTp0yWrZsadx0003G6dOnjezsbGPEiBFGrVq1DF9fX6NatWrGXXfdZfz000+X88cAAMWKvIG8oawib0B5ZjEMwyjJQgYAAAAAACg7WNoAAAAAAADcRiEBAAAAAAC4jUICAAAAAABwG4UEAAAAAADgNgoJAAAAAADAbRQSAAAAAACA2ygkAAAAAAAAt1FIAMq5Xr166c4773S8vvnmmzVo0KBij2PlypWyWCxKT0+/YB+LxaIFCxa4fc1Ro0apadOmhYrr119/lcVi0ebNmwt1HQAAyjpyhosjZwD+RiEBKAG9evWSxWKRxWKRn5+f6tatq6SkJOXm5l729/700081evRot/q684ccAABcPuQMAEojn5IOADCrjh07asaMGcrKytKSJUs0YMAA+fr6atiwYXn6Zmdny8/Pr0jet1KlSkVyHQAAUDzIGQCUNsxIAEqIv7+/IiIiFB0drf79+ys+Pl4LFy6U9PfUwpdeekmRkZFq0KCBJOngwYO65557FBYWpkqVKqlLly769ddfHde02Wx68sknFRYWpsqVK+vpp5+WYRhO7+s6TTErK0vPPPOMoqKi5O/vr7p162r69On69ddfdcstt0iSKlasKIvFol69ekmS7Ha7kpOTVbt2bQUGBuqaa67Rxx9/7PQ+S5YsUf369RUYGKhbbrnFKU53PfPMM6pfv74qVKigOnXqaPjw4crJycnT76233lJUVJQqVKige+65RydPnnQ6/+6776pRo0YKCAhQw4YNNWXKlALHAgBASSFnuDRyBqB4UUgASonAwEBlZ2c7Xq9YsUI7duzQsmXLtGjRIuXk5CghIUEhISH65ptvtHbtWgUHB6tjx46Oca+99ppmzpyp9957T2vWrNHx48c1f/78i75vjx499MEHH2jixInavn273nrrLQUHBysqKkqffPKJJGnHjh06cuSI3njjDUlScnKyZs+erWnTpmnr1q0aPHiwHnjgAa1atUrSueSla9euuv3227V582Y9/PDDevbZZwv8MwkJCdHMmTO1bds2vfHGG3rnnXc0fvx4pz67d+/WvHnz9Nlnn2np0qX64Ycf9OijjzrOz5kzRyNGjNBLL72k7du3a8yYMRo+fLhmzZpV4HgAACgNyBnyImcAipkBoNj17NnT6NKli2EYhmG3241ly5YZ/v7+xpAhQxznw8PDjaysLMeY//znP0aDBg0Mu93uaMvKyjICAwONL774wjAMw6hWrZoxbtw4x/mcnByjRo0ajvcyDMNo06aN8cQTTxiGYRg7duwwJBnLli3LN86vv/7akGScOHHC0ZaZmWlUqFDBWLdunVPfPn36GPfdd59hGIYxbNgwIyYmxun8M888k+dariQZ8+fPv+D5V155xWjWrJnj9ciRIw1vb2/jt99+c7R9/vnnhpeXl3HkyBHDMAzjyiuvNObOnet0ndGjRxtxcXGGYRjGvn37DEnGDz/8cMH3BQCgpJAz5I+cAShZ7JEAlJBFixYpODhYOTk5stvtuv/++zVq1CjH+caNGzutcfzxxx+1e/duhYSEOF0nMzNTe/bs0cmTJ3XkyBHFxsY6zvn4+Kh58+Z5piqet3nzZnl7e6tNmzZux717926dPXtW7du3d2rPzs7WtddeK0navn27UxySFBcX5/Z7nPff//5XEydO1J49e3T69Gnl5ubKarU69alZs6aqV6/u9D52u107duxQSEiI9uzZoz59+qhv376OPrm5uQoNDS1wPAAAlARyhksjZwCKF4UEoITccsstmjp1qvz8/BQZGSkfH+f/OwYFBTm9Pn36tJo1a6Y5c+bkuVaVKlU8iiEwMLDAY06fPi1JWrx4sdMfY+ncGs6ikpKSosTERL3wwgtKSEhQaGioPvzwQ7322msFjvWdd97Jk6R4e3sXWawAAFxO5AwXR84AFD8KCUAJCQoKUt26dd3uf9111+m///2vqlatmqfCfl61atW0YcMG3XTTTZLOVdE3bdqk6667Lt/+jRs3lt1u16pVqxQfH5/n/Pm7GzabzdEWExMjf39/HThw4IJ3JRo1auTYBOq89evXX/pD/sO6desUHR2tf//73462/fv35+l34MABHT58WJGRkY738fLyUoMGDRQeHq7IyEjt3btXiYmJBXp/AABKC3KGiyNnAIofmy0CZURiYqKuuOIKdenSRd9884327dunlStX6vHHH9dvv/0mSXriiSf08ssva8GCBfrll1/06KOPXvR5zrVq1VLPnj310EMPacGCBY5rzps3T5IU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CQm5UDUBAOB+BAIAAADnVa4eCZ6enrrpppuUm5t7gcoBAAAAAABVWbmbLbZu3Vr79++/ELUAAFA1GBXcKmDatGkymUx69NFHrWOFhYUaMWKE6tatK39/f/Xp00dHjhyxOS87O1u9e/dW7dq1Vb9+fY0ZM0alpaUVKwYAAOA8yh0kTJkyRaNHj9aqVat06NAh5efn22wAAFzqzvZIcHVz1TfffKP58+erTZs2NuNJSUlauXKl3n//faWnp+vgwYM2zY/LysrUu3dvFRcXa9OmTVq4cKHS0tI0btw414sBAABwwOkgYdKkSTp58qRuvvlmbd++XbfddpsaN26skJAQhYSEKDg4mL4JAIDqwQ0zEgoKCjRgwAC99tprNn+f5uXl6fXXX9fzzz+vG264QR07dlRqaqo2bdqkr776SpL073//W7t379abb76pdu3aqVevXpo8ebJeeuklFRcXu1YQAACAA043W5w4caL+8Y9/6PPPP7+Q9QAAUC3Yz9Izm80ym80Ojx8xYoR69+6t+Ph4TZkyxTq+detWlZSUKD4+3jp2xRVXqEmTJsrIyNA111yjjIwMxcTEqEGDBtZjEhISNGzYMO3atUvt27evxHcGAABqOqeDBMM48yuWbt26XbBiAACoCirj8Y/h4eE24+PHj9eECRPOe84777yjb7/9Vt988805+w4fPixvb28FBwfbjDdo0ECHDx+2HvPHEOHs/rP7AAAAKlO5Hv9oMpkuVB0AAFQdFWma+N/zcnJyFBgYaB12NBshJydHjzzyiNauXSsfHx8XbwoAAHDxlCtIaNmy5V+GCcePH69QQQAAuF0lBAmBgYE2QYIjW7du1dGjR9WhQwfrWFlZmb744gu9+OKL+uSTT1RcXKzc3FybWQlHjhxRaGioJCk0NFRff/21zXXPPtXh7DEAAACVpVxBwsSJExUUFHShagEAoMa58cYbtXPnTpux+++/X1dccYWefPJJhYeHq1atWlq3bp369OkjScrKylJ2drbi4uIkSXFxcXr22Wd19OhR1a9fX5K0du1aBQYGKjo6+uK+IQAAUO2VK0jo37+/9QcUAACqq8rokeCsgIAAtW7d2mbMz89PdevWtY4PGTJEjz32mOrUqaPAwEA9/PDDiouL0zXXXCNJuummmxQdHa17771XM2bM0OHDh/XMM89oxIgRf9rgEQAAwBVO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cOFC7du3T99++63mzp2rhQsXuvrx4SL67bffdMMNN+jNN9/Ujh079NNPP+n999/XjBkzrN+Bpk2bat26dTp8+PCfPt40Pj7e+t3/9ttv9fXXX+u+++5Tt27d1KlTJ5tj/fz8tHr1anl5ealXr14qKChQy5YtNWDAAN1333364IMP9NNPP+nrr79WSkqKVq9efUE/BwAAANRsBAmoEiZNmiSLxWIz1qFDB7333nt655131Lp1a40bN06TJk3S4MGDbc77+eefdfnll9usP/+j4OBgvfbaa+rcubPatGmjTz/9VCtXrlTdunWdvsZZqamp6tixo2655RbFxcXJMAytWbNGtWrVOudYLy8vvf3227ryyit1ww036OjRo5o8ebKSk5OVkpKiqKgo9ezZU6tXr1ZkZGQ5PzG4g7+/v2JjYzVr1ix17dpVrVu3VnJysoYOHaoXX3xRkjRz5kytXbtW4eHhat++vcNrmUwmffjhhwoJCVHXrl0VHx+vZs2a6d1333V4748++kiGYah37946efKkUlNTdd999+nxxx9Xq1atdPvtt+ubb75RkyZNLsj7BwAAACTJZBiG4e4iAAAAAADApYEZCQAAAAAAwGkECQAAAAAAwGkECQAAAAAAwGkECQAAAAAAwGkECQAAAAAAwGkECQAAAAAAwGkECQAAAAAAwGkECQAAAAAAwGkECUA1N3jwYN1+++3W19dff70effTRi17H+vXrZTKZlJub6/AYk8mk5cuXO33NCRMmqF27dhWq6+eff5bJZNK2bdsqdB0AAACgpiBIANxg8ODBMplMMplM8vb2VvPmzTVp0iSVlpZe8Ht/8MEHmjx5slPHOvOPfwAAAAA1i5e7CwBqqp49eyo1NVVFRUVas2aNRowYoVq1amns2LHnHFtcXCxvb+9KuW+dOnUq5ToAAAAAaiZmJABuYjabFRoaqoiICA0bNkzx8fFasWKFpP8tR3j22WcVFhamVq1aSZJycnLUr18/BQcHq06dOkpMTNTPP/9svWZZWZkee+wxBQcHq27dunriiSdkGIbNfe2XNhQVFenJJ59UeHi4zGazmjdvrtdff10///yzunfvLkkKCQmRyWTS4MGDJUkWi0UpKSmKjIyUr6+v2rZtqyVLltjcZ82aNWrZsqV8fX3VvXt3mzqd9eSTT6ply5aqXbu2mjVrpuTkZJWU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",
|
||
"text/plain": [
|
||
"<Figure size 1200x1000 with 6 Axes>"
|
||
]
|
||
},
|
||
"metadata": {},
|
||
"output_type": "display_data"
|
||
}
|
||
],
|
||
"source": [
|
||
"from sklearn.metrics import ConfusionMatrixDisplay\n",
|
||
"import matplotlib.pyplot as plt\n",
|
||
"import numpy as np\n",
|
||
"\n",
|
||
"# Цветовая схема: светло-голубой для правильных, бледно-красный для ошибок\n",
|
||
"def custom_color_map(c_matrix):\n",
|
||
" colors = np.empty_like(c_matrix, dtype=str)\n",
|
||
" for i in range(c_matrix.shape[0]):\n",
|
||
" for j in range(c_matrix.shape[1]):\n",
|
||
" if i == j:\n",
|
||
" colors[i, j] = \"#add8e6\" # Светло-голубой\n",
|
||
" else:\n",
|
||
" colors[i, j] = \"#f08080\" # Бледно-красный\n",
|
||
" return colors\n",
|
||
"\n",
|
||
"fig, ax = plt.subplots(2, 2, figsize=(12, 10))\n",
|
||
"\n",
|
||
"for index, (key, model_info) in enumerate(class_models.items()):\n",
|
||
" c_matrix = model_info[\"Confusion_matrix\"]\n",
|
||
"\n",
|
||
" # Генерация кастомных цветов\n",
|
||
" disp = ConfusionMatrixDisplay(\n",
|
||
" confusion_matrix=c_matrix, display_labels=[\"Not stroke\", \"Stroke\"]\n",
|
||
" )\n",
|
||
" disp.plot(ax=ax.flat[index], cmap=custom_color_map(c_matrix), colorbar=False)\n",
|
||
"\n",
|
||
" disp.ax_.set_title(key)\n",
|
||
"\n",
|
||
"if len(class_models) < len(ax.flat):\n",
|
||
" for i in range(len(class_models), len(ax.flat)):\n",
|
||
" fig.delaxes(ax.flat[i])\n",
|
||
"\n",
|
||
"plt.subplots_adjust(top=0.9, bottom=0.1, hspace=0.4, wspace=0.3)\n",
|
||
"plt.show()\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"Precision, Recall, Accuracy, F1:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 10,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/html": [
|
||
"<style type=\"text/css\">\n",
|
||
"#T_0e668_row0_col0 {\n",
|
||
" background-color: #1f988b;\n",
|
||
" color: #f1f1f1;\n",
|
||
"}\n",
|
||
"#T_0e668_row0_col1, #T_0e668_row1_col0, #T_0e668_row1_col2, #T_0e668_row2_col3 {\n",
|
||
" background-color: #a8db34;\n",
|
||
" color: #000000;\n",
|
||
"}\n",
|
||
"#T_0e668_row0_col2, #T_0e668_row0_col3, #T_0e668_row1_col1, #T_0e668_row2_col0 {\n",
|
||
" background-color: #26818e;\n",
|
||
" color: #f1f1f1;\n",
|
||
"}\n",
|
||
"#T_0e668_row0_col4 {\n",
|
||
" background-color: #b7318a;\n",
|
||
" color: #f1f1f1;\n",
|
||
"}\n",
|
||
"#T_0e668_row0_col5, #T_0e668_row1_col4, #T_0e668_row1_col6, #T_0e668_row2_col7 {\n",
|
||
" background-color: #da5a6a;\n",
|
||
" color: #f1f1f1;\n",
|
||
"}\n",
|
||
"#T_0e668_row0_col6, #T_0e668_row0_col7, #T_0e668_row2_col4, #T_0e668_row2_col5 {\n",
|
||
" background-color: #4e02a2;\n",
|
||
" color: #f1f1f1;\n",
|
||
"}\n",
|
||
"#T_0e668_row1_col3, #T_0e668_row2_col1 {\n",
|
||
" background-color: #1f968b;\n",
|
||
" color: #f1f1f1;\n",
|
||
"}\n",
|
||
"#T_0e668_row1_col5 {\n",
|
||
" background-color: #be3885;\n",
|
||
" color: #f1f1f1;\n",
|
||
"}\n",
|
||
"#T_0e668_row1_col7 {\n",
|
||
" background-color: #9c179e;\n",
|
||
" color: #f1f1f1;\n",
|
||
"}\n",
|
||
"#T_0e668_row2_col2 {\n",
|
||
" background-color: #86d549;\n",
|
||
" color: #000000;\n",
|
||
"}\n",
|
||
"#T_0e668_row2_col6 {\n",
|
||
" background-color: #8808a6;\n",
|
||
" color: #f1f1f1;\n",
|
||
"}\n",
|
||
"</style>\n",
|
||
"<table id=\"T_0e668\">\n",
|
||
" <thead>\n",
|
||
" <tr>\n",
|
||
" <th class=\"blank level0\" > </th>\n",
|
||
" <th id=\"T_0e668_level0_col0\" class=\"col_heading level0 col0\" >Precision_train</th>\n",
|
||
" <th id=\"T_0e668_level0_col1\" class=\"col_heading level0 col1\" >Precision_test</th>\n",
|
||
" <th id=\"T_0e668_level0_col2\" class=\"col_heading level0 col2\" >Recall_train</th>\n",
|
||
" <th id=\"T_0e668_level0_col3\" class=\"col_heading level0 col3\" >Recall_test</th>\n",
|
||
" <th id=\"T_0e668_level0_col4\" class=\"col_heading level0 col4\" >Accuracy_train</th>\n",
|
||
" <th id=\"T_0e668_level0_col5\" class=\"col_heading level0 col5\" >Accuracy_test</th>\n",
|
||
" <th id=\"T_0e668_level0_col6\" class=\"col_heading level0 col6\" >F1_train</th>\n",
|
||
" <th id=\"T_0e668_level0_col7\" class=\"col_heading level0 col7\" >F1_test</th>\n",
|
||
" </tr>\n",
|
||
" </thead>\n",
|
||
" <tbody>\n",
|
||
" <tr>\n",
|
||
" <th id=\"T_0e668_level0_row0\" class=\"row_heading level0 row0\" >mlp</th>\n",
|
||
" <td id=\"T_0e668_row0_col0\" class=\"data row0 col0\" >0.400000</td>\n",
|
||
" <td id=\"T_0e668_row0_col1\" class=\"data row0 col1\" >0.200000</td>\n",
|
||
" <td id=\"T_0e668_row0_col2\" class=\"data row0 col2\" >0.020101</td>\n",
|
||
" <td id=\"T_0e668_row0_col3\" class=\"data row0 col3\" >0.020000</td>\n",
|
||
" <td id=\"T_0e668_row0_col4\" class=\"data row0 col4\" >0.950832</td>\n",
|
||
" <td id=\"T_0e668_row0_col5\" class=\"data row0 col5\" >0.948141</td>\n",
|
||
" <td id=\"T_0e668_row0_col6\" class=\"data row0 col6\" >0.038278</td>\n",
|
||
" <td id=\"T_0e668_row0_col7\" class=\"data row0 col7\" >0.036364</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th id=\"T_0e668_level0_row1\" class=\"row_heading level0 row1\" >knn</th>\n",
|
||
" <td id=\"T_0e668_row1_col0\" class=\"data row1 col0\" >1.000000</td>\n",
|
||
" <td id=\"T_0e668_row1_col1\" class=\"data row1 col1\" >0.117647</td>\n",
|
||
" <td id=\"T_0e668_row1_col2\" class=\"data row1 col2\" >1.000000</td>\n",
|
||
" <td id=\"T_0e668_row1_col3\" class=\"data row1 col3\" >0.120000</td>\n",
|
||
" <td id=\"T_0e668_row1_col4\" class=\"data row1 col4\" >1.000000</td>\n",
|
||
" <td id=\"T_0e668_row1_col5\" class=\"data row1 col5\" >0.912916</td>\n",
|
||
" <td id=\"T_0e668_row1_col6\" class=\"data row1 col6\" >1.000000</td>\n",
|
||
" <td id=\"T_0e668_row1_col7\" class=\"data row1 col7\" >0.118812</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th id=\"T_0e668_level0_row2\" class=\"row_heading level0 row2\" >random_forest</th>\n",
|
||
" <td id=\"T_0e668_row2_col0\" class=\"data row2 col0\" >0.228869</td>\n",
|
||
" <td id=\"T_0e668_row2_col1\" class=\"data row2 col1\" >0.135135</td>\n",
|
||
" <td id=\"T_0e668_row2_col2\" class=\"data row2 col2\" >0.884422</td>\n",
|
||
" <td id=\"T_0e668_row2_col3\" class=\"data row2 col3\" >0.500000</td>\n",
|
||
" <td id=\"T_0e668_row2_col4\" class=\"data row2 col4\" >0.849315</td>\n",
|
||
" <td id=\"T_0e668_row2_col5\" class=\"data row2 col5\" >0.818982</td>\n",
|
||
" <td id=\"T_0e668_row2_col6\" class=\"data row2 col6\" >0.363636</td>\n",
|
||
" <td id=\"T_0e668_row2_col7\" class=\"data row2 col7\" >0.212766</td>\n",
|
||
" </tr>\n",
|
||
" </tbody>\n",
|
||
"</table>\n"
|
||
],
|
||
"text/plain": [
|
||
"<pandas.io.formats.style.Styler at 0x1bdc4916000>"
|
||
]
|
||
},
|
||
"execution_count": 10,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"class_metrics = pd.DataFrame.from_dict(class_models, \"index\")[\n",
|
||
" [\n",
|
||
" \"Precision_train\",\n",
|
||
" \"Precision_test\",\n",
|
||
" \"Recall_train\",\n",
|
||
" \"Recall_test\",\n",
|
||
" \"Accuracy_train\",\n",
|
||
" \"Accuracy_test\",\n",
|
||
" \"F1_train\",\n",
|
||
" \"F1_test\",\n",
|
||
" ]\n",
|
||
"]\n",
|
||
"class_metrics.sort_values(\n",
|
||
" by=\"Accuracy_test\", ascending=False\n",
|
||
").style.background_gradient(\n",
|
||
" cmap=\"plasma\",\n",
|
||
" low=0.3,\n",
|
||
" high=1,\n",
|
||
" subset=[\"Accuracy_train\", \"Accuracy_test\", \"F1_train\", \"F1_test\"],\n",
|
||
").background_gradient(\n",
|
||
" cmap=\"viridis\",\n",
|
||
" low=1,\n",
|
||
" high=0.3,\n",
|
||
" subset=[\n",
|
||
" \"Precision_train\",\n",
|
||
" \"Precision_test\",\n",
|
||
" \"Recall_train\",\n",
|
||
" \"Recall_test\",\n",
|
||
" ],\n",
|
||
")"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"#### Анализ моделей:\n",
|
||
"##### MLP (многослойный перцептрон):\n",
|
||
"Точность (Accuracy): 95% (обучение и тест).\n",
|
||
"Precision и Recall: крайне низкие (0.40 и 0.02 на обучении, 0.20 и 0.02 на тесте).\n",
|
||
"F1-метрика: практически нулевая (0.038 и 0.037).\n",
|
||
"Вывод: модель хорошо определяет общий класс, но почти не замечает положительные примеры.\n",
|
||
"\n",
|
||
"##### KNN (K-ближайшие соседи):\n",
|
||
"Обучение: идеальные метрики (1.0).\n",
|
||
"Тест: резкое падение (Precision 0.118, Recall 0.12, Accuracy 91%).\n",
|
||
"Вывод: переобучение. Отлично работает на обучении, но плохо обобщает на новых данных.\n",
|
||
"\n",
|
||
"##### Random Forest (случайный лес):\n",
|
||
"Accuracy: 85% (обучение) и 82% (тест).\n",
|
||
"Precision и Recall: умеренные, но низкие на тесте (0.135 и 0.50).\n",
|
||
"F1: лучше других моделей (0.213 на тесте).\n",
|
||
"\n",
|
||
"##### Вывод: баланс метрик лучше, чем у других, но точность распознавания положительных примеров всё еще оставляет желать лучшего.\n",
|
||
"Сравнение с baseline:\n",
|
||
"Baseline (простая модель):\n",
|
||
"Accuracy 52%, Precision 0.058, Recall 0.58, F1 0.106.\n",
|
||
"Победитель по Accuracy: все модели значительно превосходят baseline.\n",
|
||
"Recall: Random Forest лучше baseline, MLP и KNN уступают.\n",
|
||
"F1-метрика: Random Forest снова впереди, но до желаемого уровня ещё далеко.\n",
|
||
"\n",
|
||
"##### Заключение:\n",
|
||
"MLP: сильно смещена, игнорирует положительные примеры.\n",
|
||
"KNN: высокая дисперсия, сильно переобучена.\n",
|
||
"Random Forest: самый сбалансированный вариант, но precision нужно улучшать.\n",
|
||
"Итог: Random Forest – лучший выбор из предложенных, но требует доработки."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Регрессия\n",
|
||
"\n",
|
||
"Разделим набор данных на на обучающую и тестовые выборки (80/20). Целевой признак - avg_glucose_level"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 11,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"'X_train'"
|
||
]
|
||
},
|
||
"metadata": {},
|
||
"output_type": "display_data"
|
||
},
|
||
{
|
||
"data": {
|
||
"text/html": [
|
||
"<div>\n",
|
||
"<style scoped>\n",
|
||
" .dataframe tbody tr th:only-of-type {\n",
|
||
" vertical-align: middle;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .dataframe tbody tr th {\n",
|
||
" vertical-align: top;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .dataframe thead th {\n",
|
||
" text-align: right;\n",
|
||
" }\n",
|
||
"</style>\n",
|
||
"<table border=\"1\" class=\"dataframe\">\n",
|
||
" <thead>\n",
|
||
" <tr style=\"text-align: right;\">\n",
|
||
" <th></th>\n",
|
||
" <th>gender</th>\n",
|
||
" <th>age</th>\n",
|
||
" <th>hypertension</th>\n",
|
||
" <th>heart_disease</th>\n",
|
||
" <th>ever_married</th>\n",
|
||
" <th>work_type</th>\n",
|
||
" <th>Residence_type</th>\n",
|
||
" <th>bmi</th>\n",
|
||
" <th>smoking_status</th>\n",
|
||
" <th>stroke</th>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>id</th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" </tr>\n",
|
||
" </thead>\n",
|
||
" <tbody>\n",
|
||
" <tr>\n",
|
||
" <th>13276</th>\n",
|
||
" <td>Female</td>\n",
|
||
" <td>38.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>Yes</td>\n",
|
||
" <td>Private</td>\n",
|
||
" <td>Urban</td>\n",
|
||
" <td>22.6</td>\n",
|
||
" <td>Unknown</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>21346</th>\n",
|
||
" <td>Female</td>\n",
|
||
" <td>12.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>No</td>\n",
|
||
" <td>children</td>\n",
|
||
" <td>Rural</td>\n",
|
||
" <td>17.8</td>\n",
|
||
" <td>Unknown</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>59178</th>\n",
|
||
" <td>Female</td>\n",
|
||
" <td>7.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>No</td>\n",
|
||
" <td>children</td>\n",
|
||
" <td>Urban</td>\n",
|
||
" <td>22.3</td>\n",
|
||
" <td>Unknown</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>1679</th>\n",
|
||
" <td>Male</td>\n",
|
||
" <td>35.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>Yes</td>\n",
|
||
" <td>Private</td>\n",
|
||
" <td>Rural</td>\n",
|
||
" <td>NaN</td>\n",
|
||
" <td>formerly smoked</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>1534</th>\n",
|
||
" <td>Female</td>\n",
|
||
" <td>61.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>Yes</td>\n",
|
||
" <td>Private</td>\n",
|
||
" <td>Rural</td>\n",
|
||
" <td>26.1</td>\n",
|
||
" <td>smokes</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>...</th>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>30463</th>\n",
|
||
" <td>Male</td>\n",
|
||
" <td>29.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>No</td>\n",
|
||
" <td>Private</td>\n",
|
||
" <td>Urban</td>\n",
|
||
" <td>29.4</td>\n",
|
||
" <td>formerly smoked</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>41935</th>\n",
|
||
" <td>Male</td>\n",
|
||
" <td>34.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>No</td>\n",
|
||
" <td>Private</td>\n",
|
||
" <td>Rural</td>\n",
|
||
" <td>33.9</td>\n",
|
||
" <td>never smoked</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>68483</th>\n",
|
||
" <td>Female</td>\n",
|
||
" <td>60.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>Yes</td>\n",
|
||
" <td>Private</td>\n",
|
||
" <td>Urban</td>\n",
|
||
" <td>41.2</td>\n",
|
||
" <td>formerly smoked</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>38617</th>\n",
|
||
" <td>Male</td>\n",
|
||
" <td>28.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>Yes</td>\n",
|
||
" <td>Self-employed</td>\n",
|
||
" <td>Urban</td>\n",
|
||
" <td>29.9</td>\n",
|
||
" <td>never smoked</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>46527</th>\n",
|
||
" <td>Male</td>\n",
|
||
" <td>53.0</td>\n",
|
||
" <td>1</td>\n",
|
||
" <td>1</td>\n",
|
||
" <td>Yes</td>\n",
|
||
" <td>Govt_job</td>\n",
|
||
" <td>Rural</td>\n",
|
||
" <td>41.9</td>\n",
|
||
" <td>never smoked</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" </tbody>\n",
|
||
"</table>\n",
|
||
"<p>4088 rows × 10 columns</p>\n",
|
||
"</div>"
|
||
],
|
||
"text/plain": [
|
||
" gender age hypertension heart_disease ever_married work_type \\\n",
|
||
"id \n",
|
||
"13276 Female 38.0 0 0 Yes Private \n",
|
||
"21346 Female 12.0 0 0 No children \n",
|
||
"59178 Female 7.0 0 0 No children \n",
|
||
"1679 Male 35.0 0 0 Yes Private \n",
|
||
"1534 Female 61.0 0 0 Yes Private \n",
|
||
"... ... ... ... ... ... ... \n",
|
||
"30463 Male 29.0 0 0 No Private \n",
|
||
"41935 Male 34.0 0 0 No Private \n",
|
||
"68483 Female 60.0 0 0 Yes Private \n",
|
||
"38617 Male 28.0 0 0 Yes Self-employed \n",
|
||
"46527 Male 53.0 1 1 Yes Govt_job \n",
|
||
"\n",
|
||
" Residence_type bmi smoking_status stroke \n",
|
||
"id \n",
|
||
"13276 Urban 22.6 Unknown 0 \n",
|
||
"21346 Rural 17.8 Unknown 0 \n",
|
||
"59178 Urban 22.3 Unknown 0 \n",
|
||
"1679 Rural NaN formerly smoked 0 \n",
|
||
"1534 Rural 26.1 smokes 0 \n",
|
||
"... ... ... ... ... \n",
|
||
"30463 Urban 29.4 formerly smoked 0 \n",
|
||
"41935 Rural 33.9 never smoked 0 \n",
|
||
"68483 Urban 41.2 formerly smoked 0 \n",
|
||
"38617 Urban 29.9 never smoked 0 \n",
|
||
"46527 Rural 41.9 never smoked 0 \n",
|
||
"\n",
|
||
"[4088 rows x 10 columns]"
|
||
]
|
||
},
|
||
"metadata": {},
|
||
"output_type": "display_data"
|
||
},
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"'y_train'"
|
||
]
|
||
},
|
||
"metadata": {},
|
||
"output_type": "display_data"
|
||
},
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"id\n",
|
||
"13276 71.06\n",
|
||
"21346 70.13\n",
|
||
"59178 86.75\n",
|
||
"1679 77.48\n",
|
||
"1534 99.35\n",
|
||
" ... \n",
|
||
"30463 82.93\n",
|
||
"41935 125.29\n",
|
||
"68483 65.38\n",
|
||
"38617 73.98\n",
|
||
"46527 109.51\n",
|
||
"Name: avg_glucose_level, Length: 4088, dtype: float64"
|
||
]
|
||
},
|
||
"metadata": {},
|
||
"output_type": "display_data"
|
||
},
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"'X_test'"
|
||
]
|
||
},
|
||
"metadata": {},
|
||
"output_type": "display_data"
|
||
},
|
||
{
|
||
"data": {
|
||
"text/html": [
|
||
"<div>\n",
|
||
"<style scoped>\n",
|
||
" .dataframe tbody tr th:only-of-type {\n",
|
||
" vertical-align: middle;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .dataframe tbody tr th {\n",
|
||
" vertical-align: top;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .dataframe thead th {\n",
|
||
" text-align: right;\n",
|
||
" }\n",
|
||
"</style>\n",
|
||
"<table border=\"1\" class=\"dataframe\">\n",
|
||
" <thead>\n",
|
||
" <tr style=\"text-align: right;\">\n",
|
||
" <th></th>\n",
|
||
" <th>gender</th>\n",
|
||
" <th>age</th>\n",
|
||
" <th>hypertension</th>\n",
|
||
" <th>heart_disease</th>\n",
|
||
" <th>ever_married</th>\n",
|
||
" <th>work_type</th>\n",
|
||
" <th>Residence_type</th>\n",
|
||
" <th>bmi</th>\n",
|
||
" <th>smoking_status</th>\n",
|
||
" <th>stroke</th>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>id</th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" </tr>\n",
|
||
" </thead>\n",
|
||
" <tbody>\n",
|
||
" <tr>\n",
|
||
" <th>8385</th>\n",
|
||
" <td>Male</td>\n",
|
||
" <td>37.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>Yes</td>\n",
|
||
" <td>Private</td>\n",
|
||
" <td>Urban</td>\n",
|
||
" <td>35.9</td>\n",
|
||
" <td>Unknown</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>937</th>\n",
|
||
" <td>Male</td>\n",
|
||
" <td>7.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>No</td>\n",
|
||
" <td>children</td>\n",
|
||
" <td>Urban</td>\n",
|
||
" <td>NaN</td>\n",
|
||
" <td>Unknown</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>3494</th>\n",
|
||
" <td>Female</td>\n",
|
||
" <td>80.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>Yes</td>\n",
|
||
" <td>Private</td>\n",
|
||
" <td>Rural</td>\n",
|
||
" <td>26.7</td>\n",
|
||
" <td>Unknown</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>23850</th>\n",
|
||
" <td>Male</td>\n",
|
||
" <td>66.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>Yes</td>\n",
|
||
" <td>Private</td>\n",
|
||
" <td>Urban</td>\n",
|
||
" <td>33.1</td>\n",
|
||
" <td>never smoked</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>31156</th>\n",
|
||
" <td>Female</td>\n",
|
||
" <td>49.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>Yes</td>\n",
|
||
" <td>Private</td>\n",
|
||
" <td>Urban</td>\n",
|
||
" <td>29.8</td>\n",
|
||
" <td>never smoked</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>...</th>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>71010</th>\n",
|
||
" <td>Female</td>\n",
|
||
" <td>80.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>No</td>\n",
|
||
" <td>Self-employed</td>\n",
|
||
" <td>Urban</td>\n",
|
||
" <td>22.8</td>\n",
|
||
" <td>never smoked</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>39518</th>\n",
|
||
" <td>Female</td>\n",
|
||
" <td>20.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>No</td>\n",
|
||
" <td>Private</td>\n",
|
||
" <td>Rural</td>\n",
|
||
" <td>20.7</td>\n",
|
||
" <td>never smoked</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>7780</th>\n",
|
||
" <td>Male</td>\n",
|
||
" <td>51.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>Yes</td>\n",
|
||
" <td>Self-employed</td>\n",
|
||
" <td>Urban</td>\n",
|
||
" <td>30.7</td>\n",
|
||
" <td>never smoked</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>56137</th>\n",
|
||
" <td>Female</td>\n",
|
||
" <td>62.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>Yes</td>\n",
|
||
" <td>Private</td>\n",
|
||
" <td>Urban</td>\n",
|
||
" <td>36.3</td>\n",
|
||
" <td>Unknown</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>33175</th>\n",
|
||
" <td>Female</td>\n",
|
||
" <td>57.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>Yes</td>\n",
|
||
" <td>Govt_job</td>\n",
|
||
" <td>Urban</td>\n",
|
||
" <td>28.5</td>\n",
|
||
" <td>Unknown</td>\n",
|
||
" <td>1</td>\n",
|
||
" </tr>\n",
|
||
" </tbody>\n",
|
||
"</table>\n",
|
||
"<p>1022 rows × 10 columns</p>\n",
|
||
"</div>"
|
||
],
|
||
"text/plain": [
|
||
" gender age hypertension heart_disease ever_married work_type \\\n",
|
||
"id \n",
|
||
"8385 Male 37.0 0 0 Yes Private \n",
|
||
"937 Male 7.0 0 0 No children \n",
|
||
"3494 Female 80.0 0 0 Yes Private \n",
|
||
"23850 Male 66.0 0 0 Yes Private \n",
|
||
"31156 Female 49.0 0 0 Yes Private \n",
|
||
"... ... ... ... ... ... ... \n",
|
||
"71010 Female 80.0 0 0 No Self-employed \n",
|
||
"39518 Female 20.0 0 0 No Private \n",
|
||
"7780 Male 51.0 0 0 Yes Self-employed \n",
|
||
"56137 Female 62.0 0 0 Yes Private \n",
|
||
"33175 Female 57.0 0 0 Yes Govt_job \n",
|
||
"\n",
|
||
" Residence_type bmi smoking_status stroke \n",
|
||
"id \n",
|
||
"8385 Urban 35.9 Unknown 0 \n",
|
||
"937 Urban NaN Unknown 0 \n",
|
||
"3494 Rural 26.7 Unknown 0 \n",
|
||
"23850 Urban 33.1 never smoked 0 \n",
|
||
"31156 Urban 29.8 never smoked 0 \n",
|
||
"... ... ... ... ... \n",
|
||
"71010 Urban 22.8 never smoked 0 \n",
|
||
"39518 Rural 20.7 never smoked 0 \n",
|
||
"7780 Urban 30.7 never smoked 0 \n",
|
||
"56137 Urban 36.3 Unknown 0 \n",
|
||
"33175 Urban 28.5 Unknown 1 \n",
|
||
"\n",
|
||
"[1022 rows x 10 columns]"
|
||
]
|
||
},
|
||
"metadata": {},
|
||
"output_type": "display_data"
|
||
},
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"'y_test'"
|
||
]
|
||
},
|
||
"metadata": {},
|
||
"output_type": "display_data"
|
||
},
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"id\n",
|
||
"8385 90.78\n",
|
||
"937 87.94\n",
|
||
"3494 102.90\n",
|
||
"23850 103.01\n",
|
||
"31156 105.99\n",
|
||
" ... \n",
|
||
"71010 57.57\n",
|
||
"39518 78.94\n",
|
||
"7780 75.73\n",
|
||
"56137 88.32\n",
|
||
"33175 110.52\n",
|
||
"Name: avg_glucose_level, Length: 1022, dtype: float64"
|
||
]
|
||
},
|
||
"metadata": {},
|
||
"output_type": "display_data"
|
||
}
|
||
],
|
||
"source": [
|
||
"features = ['gender', 'age', 'hypertension', 'heart_disease', 'ever_married', 'work_type', 'Residence_type', 'bmi', 'smoking_status', 'stroke']\n",
|
||
"target = 'avg_glucose_level'\n",
|
||
"\n",
|
||
"X_train, X_test, y_train, y_test = train_test_split(df[features], df[target], test_size=0.2, random_state=random_state)\n",
|
||
"\n",
|
||
"display(\"X_train\", X_train)\n",
|
||
"display(\"y_train\", y_train)\n",
|
||
"\n",
|
||
"display(\"X_test\", X_test)\n",
|
||
"display(\"y_test\", y_test)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"Выберем ориентир для задачи регрессии. Для этого применим алгоритм правила нуля, т.е. в каждом случае в качестве предсказания выберем среднее значение из области значений целевого признака."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 12,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Baseline RMSE: 44.12711275645952\n",
|
||
"Baseline RMAE: 5.662154850745081\n",
|
||
"Baseline R2: -0.0010729515309222393\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"import math\n",
|
||
"from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score\n",
|
||
"\n",
|
||
"# Базовое предсказание: среднее значение по y_train\n",
|
||
"baseline_predictions = [y_train.mean()] * len(y_test)\n",
|
||
"\n",
|
||
"# Вычисление метрик качества для ориентира\n",
|
||
"baseline_rmse = math.sqrt(\n",
|
||
" mean_squared_error(y_test, baseline_predictions)\n",
|
||
" )\n",
|
||
"baseline_rmae = math.sqrt(\n",
|
||
" mean_absolute_error(y_test, baseline_predictions)\n",
|
||
" )\n",
|
||
"baseline_r2 = r2_score(y_test, baseline_predictions)\n",
|
||
"\n",
|
||
"print('Baseline RMSE:', baseline_rmse)\n",
|
||
"print('Baseline RMAE:', baseline_rmae)\n",
|
||
"print('Baseline R2:', baseline_r2)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"#### Метрики:\n",
|
||
"##### RMSE: корень из MSE, измеряет среднеквадратическую ошибку. \n",
|
||
"Удобен, так как результат в тех же единицах, что и данные. Штрафует за большие отклонения. Хорош для задач, где важна интерпретируемость.\n",
|
||
"##### RMAE: корень из MAE, измеряет среднюю абсолютную ошибку. \n",
|
||
"Менее чувствителен к выбросам, что полезно для данных с редкими сильными отклонениями.\n",
|
||
"##### R²: коэффициент детерминации, показывает, насколько модель объясняет изменчивость данных. Значение ближе к 1 — модель хорошо описывает данные\n",
|
||
"Используется для сравнения моделей на одинаковых данных.\n",
|
||
"Эти метрики помогают оценить, насколько точна модель по сравнению с простым усреднением."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Сформируем конвейер для регрессии"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 13,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"columns_to_drop = []\n",
|
||
"columns_not_to_modify = [\"hypertension\", \"heart_disease\", \"stroke\", \"avg_glucose_level\"]\n",
|
||
"\n",
|
||
"num_columns = [\n",
|
||
" column\n",
|
||
" for column in df.columns\n",
|
||
" if column not in columns_to_drop\n",
|
||
" and column not in columns_not_to_modify\n",
|
||
" and df[column].dtype != \"object\"\n",
|
||
"]\n",
|
||
"\n",
|
||
"cat_columns = [\n",
|
||
" column\n",
|
||
" for column in df.columns\n",
|
||
" if column not in columns_to_drop\n",
|
||
" and column not in columns_not_to_modify\n",
|
||
" and df[column].dtype == \"object\"\n",
|
||
"]\n",
|
||
"\n",
|
||
"num_imputer = SimpleImputer(strategy=\"median\")\n",
|
||
"num_scaler = StandardScaler()\n",
|
||
"preprocessing_num = Pipeline(\n",
|
||
" [\n",
|
||
" (\"imputer\", num_imputer),\n",
|
||
" (\"scaler\", num_scaler),\n",
|
||
" ]\n",
|
||
")\n",
|
||
"\n",
|
||
"cat_imputer = SimpleImputer(strategy=\"constant\", fill_value=\"unknown\")\n",
|
||
"cat_encoder = OneHotEncoder(handle_unknown=\"ignore\", sparse_output=False, drop=\"first\")\n",
|
||
"preprocessing_cat = Pipeline(\n",
|
||
" [\n",
|
||
" (\"imputer\", cat_imputer),\n",
|
||
" (\"encoder\", cat_encoder),\n",
|
||
" ]\n",
|
||
")\n",
|
||
"\n",
|
||
"features_preprocessing = ColumnTransformer(\n",
|
||
" verbose_feature_names_out=False,\n",
|
||
" transformers=[\n",
|
||
" (\"prepocessing_num\", preprocessing_num, num_columns),\n",
|
||
" (\"prepocessing_cat\", preprocessing_cat, cat_columns),\n",
|
||
" ],\n",
|
||
" remainder=\"passthrough\"\n",
|
||
")\n",
|
||
"\n",
|
||
"drop_columns = ColumnTransformer(\n",
|
||
" verbose_feature_names_out=False,\n",
|
||
" transformers=[\n",
|
||
" (\"drop_columns\", \"drop\", columns_to_drop),\n",
|
||
" ],\n",
|
||
" remainder=\"passthrough\",\n",
|
||
")\n",
|
||
"\n",
|
||
"pipeline_end_reg = Pipeline(\n",
|
||
" [\n",
|
||
" (\"features_preprocessing\", features_preprocessing),\n",
|
||
" (\"drop_columns\", drop_columns),\n",
|
||
" ]\n",
|
||
")"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"Теперь проверим работу конвейера:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 14,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/html": [
|
||
"<div>\n",
|
||
"<style scoped>\n",
|
||
" .dataframe tbody tr th:only-of-type {\n",
|
||
" vertical-align: middle;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .dataframe tbody tr th {\n",
|
||
" vertical-align: top;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .dataframe thead th {\n",
|
||
" text-align: right;\n",
|
||
" }\n",
|
||
"</style>\n",
|
||
"<table border=\"1\" class=\"dataframe\">\n",
|
||
" <thead>\n",
|
||
" <tr style=\"text-align: right;\">\n",
|
||
" <th></th>\n",
|
||
" <th>age</th>\n",
|
||
" <th>bmi</th>\n",
|
||
" <th>gender_Male</th>\n",
|
||
" <th>gender_Other</th>\n",
|
||
" <th>ever_married_Yes</th>\n",
|
||
" <th>work_type_Never_worked</th>\n",
|
||
" <th>work_type_Private</th>\n",
|
||
" <th>work_type_Self-employed</th>\n",
|
||
" <th>work_type_children</th>\n",
|
||
" <th>Residence_type_Urban</th>\n",
|
||
" <th>smoking_status_formerly smoked</th>\n",
|
||
" <th>smoking_status_never smoked</th>\n",
|
||
" <th>smoking_status_smokes</th>\n",
|
||
" <th>hypertension</th>\n",
|
||
" <th>heart_disease</th>\n",
|
||
" <th>stroke</th>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>id</th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" <th></th>\n",
|
||
" </tr>\n",
|
||
" </thead>\n",
|
||
" <tbody>\n",
|
||
" <tr>\n",
|
||
" <th>13276</th>\n",
|
||
" <td>-0.236211</td>\n",
|
||
" <td>-0.826056</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>21346</th>\n",
|
||
" <td>-1.386874</td>\n",
|
||
" <td>-1.455413</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>59178</th>\n",
|
||
" <td>-1.608155</td>\n",
|
||
" <td>-0.865391</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>1679</th>\n",
|
||
" <td>-0.368980</td>\n",
|
||
" <td>-0.104918</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>1534</th>\n",
|
||
" <td>0.781682</td>\n",
|
||
" <td>-0.367150</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>...</th>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" <td>...</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>30463</th>\n",
|
||
" <td>-0.634518</td>\n",
|
||
" <td>0.065532</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>41935</th>\n",
|
||
" <td>-0.413236</td>\n",
|
||
" <td>0.655554</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>68483</th>\n",
|
||
" <td>0.737426</td>\n",
|
||
" <td>1.612701</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>38617</th>\n",
|
||
" <td>-0.678774</td>\n",
|
||
" <td>0.131090</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>46527</th>\n",
|
||
" <td>0.427632</td>\n",
|
||
" <td>1.704482</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>1</td>\n",
|
||
" <td>1</td>\n",
|
||
" <td>0</td>\n",
|
||
" </tr>\n",
|
||
" </tbody>\n",
|
||
"</table>\n",
|
||
"<p>4088 rows × 16 columns</p>\n",
|
||
"</div>"
|
||
],
|
||
"text/plain": [
|
||
" age bmi gender_Male gender_Other ever_married_Yes \\\n",
|
||
"id \n",
|
||
"13276 -0.236211 -0.826056 0.0 0.0 1.0 \n",
|
||
"21346 -1.386874 -1.455413 0.0 0.0 0.0 \n",
|
||
"59178 -1.608155 -0.865391 0.0 0.0 0.0 \n",
|
||
"1679 -0.368980 -0.104918 1.0 0.0 1.0 \n",
|
||
"1534 0.781682 -0.367150 0.0 0.0 1.0 \n",
|
||
"... ... ... ... ... ... \n",
|
||
"30463 -0.634518 0.065532 1.0 0.0 0.0 \n",
|
||
"41935 -0.413236 0.655554 1.0 0.0 0.0 \n",
|
||
"68483 0.737426 1.612701 0.0 0.0 1.0 \n",
|
||
"38617 -0.678774 0.131090 1.0 0.0 1.0 \n",
|
||
"46527 0.427632 1.704482 1.0 0.0 1.0 \n",
|
||
"\n",
|
||
" work_type_Never_worked work_type_Private work_type_Self-employed \\\n",
|
||
"id \n",
|
||
"13276 0.0 1.0 0.0 \n",
|
||
"21346 0.0 0.0 0.0 \n",
|
||
"59178 0.0 0.0 0.0 \n",
|
||
"1679 0.0 1.0 0.0 \n",
|
||
"1534 0.0 1.0 0.0 \n",
|
||
"... ... ... ... \n",
|
||
"30463 0.0 1.0 0.0 \n",
|
||
"41935 0.0 1.0 0.0 \n",
|
||
"68483 0.0 1.0 0.0 \n",
|
||
"38617 0.0 0.0 1.0 \n",
|
||
"46527 0.0 0.0 0.0 \n",
|
||
"\n",
|
||
" work_type_children Residence_type_Urban \\\n",
|
||
"id \n",
|
||
"13276 0.0 1.0 \n",
|
||
"21346 1.0 0.0 \n",
|
||
"59178 1.0 1.0 \n",
|
||
"1679 0.0 0.0 \n",
|
||
"1534 0.0 0.0 \n",
|
||
"... ... ... \n",
|
||
"30463 0.0 1.0 \n",
|
||
"41935 0.0 0.0 \n",
|
||
"68483 0.0 1.0 \n",
|
||
"38617 0.0 1.0 \n",
|
||
"46527 0.0 0.0 \n",
|
||
"\n",
|
||
" smoking_status_formerly smoked smoking_status_never smoked \\\n",
|
||
"id \n",
|
||
"13276 0.0 0.0 \n",
|
||
"21346 0.0 0.0 \n",
|
||
"59178 0.0 0.0 \n",
|
||
"1679 1.0 0.0 \n",
|
||
"1534 0.0 0.0 \n",
|
||
"... ... ... \n",
|
||
"30463 1.0 0.0 \n",
|
||
"41935 0.0 1.0 \n",
|
||
"68483 1.0 0.0 \n",
|
||
"38617 0.0 1.0 \n",
|
||
"46527 0.0 1.0 \n",
|
||
"\n",
|
||
" smoking_status_smokes hypertension heart_disease stroke \n",
|
||
"id \n",
|
||
"13276 0.0 0 0 0 \n",
|
||
"21346 0.0 0 0 0 \n",
|
||
"59178 0.0 0 0 0 \n",
|
||
"1679 0.0 0 0 0 \n",
|
||
"1534 1.0 0 0 0 \n",
|
||
"... ... ... ... ... \n",
|
||
"30463 0.0 0 0 0 \n",
|
||
"41935 0.0 0 0 0 \n",
|
||
"68483 0.0 0 0 0 \n",
|
||
"38617 0.0 0 0 0 \n",
|
||
"46527 0.0 1 1 0 \n",
|
||
"\n",
|
||
"[4088 rows x 16 columns]"
|
||
]
|
||
},
|
||
"execution_count": 14,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"preprocessing_result = pipeline_end_reg.fit_transform(X_train)\n",
|
||
"preprocessed_df = pd.DataFrame(\n",
|
||
" preprocessing_result,\n",
|
||
" columns=pipeline_end_reg.get_feature_names_out(),\n",
|
||
")\n",
|
||
"\n",
|
||
"preprocessed_df"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"Подберем оптимальные гиперпараметры для каждой из выбранных моделей методом поиска по сетке и сформируем их набор.\n",
|
||
"\n",
|
||
"knn -- k-ближайших соседей\n",
|
||
"\n",
|
||
"random_forest -- метод случайного леса (набор деревьев решений)\n",
|
||
"\n",
|
||
"mlp -- многослойный персептрон (нейронная сеть)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"d:\\code\\mai\\labs\\AIM-PIbd-31-Bakalskaya-E-D\\lab_4\\venv\\Lib\\site-packages\\numpy\\ma\\core.py:2881: RuntimeWarning: invalid value encountered in cast\n",
|
||
" _data = np.array(data, dtype=dtype, copy=copy,\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Лучшие параметры для knn: {'n_jobs': -1, 'n_neighbors': 30, 'weights': 'uniform'}\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"d:\\code\\mai\\labs\\AIM-PIbd-31-Bakalskaya-E-D\\lab_4\\venv\\Lib\\site-packages\\numpy\\ma\\core.py:2881: RuntimeWarning: invalid value encountered in cast\n",
|
||
" _data = np.array(data, dtype=dtype, copy=copy,\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Лучшие параметры для random_forest: {'criterion': 'squared_error', 'max_depth': 7, 'max_features': 'sqrt', 'n_estimators': 250, 'n_jobs': -1, 'random_state': 9}\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"# Словарь с вариантами гиперпараметров для каждой модели\n",
|
||
"param_grids = {\n",
|
||
" \"knn\": {\n",
|
||
" \"n_neighbors\": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30], \n",
|
||
" \"weights\": ['uniform', 'distance'],\n",
|
||
" \"n_jobs\": [-1]\n",
|
||
" },\n",
|
||
" \"random_forest\": {\n",
|
||
" \"n_estimators\": [10, 20, 30, 40, 50, 100, 150, 200, 250, 500],\n",
|
||
" \"max_features\": [\"sqrt\", \"log2\", 2],\n",
|
||
" \"max_depth\": [2, 3, 4, 5, 6, 7, 8, 9, 10],\n",
|
||
" \"criterion\": [\"squared_error\", \"absolute_error\", \"poisson\"],\n",
|
||
" \"random_state\": [random_state],\n",
|
||
" \"n_jobs\": [-1]\n",
|
||
" },\n",
|
||
" \"mlp\": {\n",
|
||
" \"solver\": ['adam'], \n",
|
||
" \"max_iter\": [1000, 1100, 1200, 1300, 1400, 1500, 1600, 1700, 1800, 1900, 2000], \n",
|
||
" \"alpha\": 10.0 ** -np.arange(1, 10), \n",
|
||
" \"hidden_layer_sizes\":np.arange(10, 15), \n",
|
||
" \"early_stopping\": [True, False],\n",
|
||
" \"random_state\": [random_state]\n",
|
||
" }\n",
|
||
"}\n",
|
||
"\n",
|
||
"# Создаем экземпляры моделей\n",
|
||
"models = {\n",
|
||
" \"knn\": neighbors.KNeighborsRegressor(),\n",
|
||
" \"random_forest\": ensemble.RandomForestRegressor(),\n",
|
||
" \"mlp\": neural_network.MLPRegressor()\n",
|
||
"}\n",
|
||
"\n",
|
||
"# Словарь для хранения моделей с их лучшими параметрами\n",
|
||
"class_models = {}\n",
|
||
"\n",
|
||
"# Выполнение поиска по сетке для каждой модели\n",
|
||
"for model_name, model in models.items():\n",
|
||
" # Создаем GridSearchCV для текущей модели\n",
|
||
" gs_optimizer = GridSearchCV(estimator=model, param_grid=param_grids[model_name], scoring='neg_mean_squared_error', n_jobs=-1)\n",
|
||
" \n",
|
||
" # Обучаем GridSearchCV\n",
|
||
" gs_optimizer.fit(preprocessed_df, y_train.values.ravel())\n",
|
||
" \n",
|
||
" # Получаем лучшие параметры\n",
|
||
" best_params = gs_optimizer.best_params_\n",
|
||
" print(f\"Лучшие параметры для {model_name}: {best_params}\")\n",
|
||
" \n",
|
||
" class_models[model_name] = {\n",
|
||
" \"model\": model.set_params(**best_params) # Настраиваем модель с лучшими параметрами\n",
|
||
" }"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"Далее обучим модели и оценим их качество."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"for model_name in class_models.keys():\n",
|
||
" print(f\"Model: {model_name}\")\n",
|
||
" \n",
|
||
" model = class_models[model_name][\"model\"]\n",
|
||
" model_pipeline = Pipeline([(\"pipeline\", pipeline_end_reg), (\"model\", model)])\n",
|
||
" model_pipeline = model_pipeline.fit(X_train, y_train.values.ravel())\n",
|
||
"\n",
|
||
" y_train_pred = model_pipeline.predict(X_train)\n",
|
||
" y_test_pred = model_pipeline.predict(X_test)\n",
|
||
"\n",
|
||
" class_models[model_name][\"pipeline\"] = model_pipeline\n",
|
||
" class_models[model_name][\"train_preds\"] = y_train_pred\n",
|
||
" class_models[model_name][\"preds\"] = y_test_pred\n",
|
||
" \n",
|
||
" class_models[model_name][\"RMSE_train\"] = math.sqrt(\n",
|
||
" mean_squared_error(y_train, y_train_pred)\n",
|
||
" )\n",
|
||
" class_models[model_name][\"RMSE_test\"] = math.sqrt(\n",
|
||
" mean_squared_error(y_test, y_test_pred)\n",
|
||
" )\n",
|
||
" class_models[model_name][\"RMAE_test\"] = math.sqrt(\n",
|
||
" mean_absolute_error(y_test, y_test_pred)\n",
|
||
" )\n",
|
||
" class_models[model_name][\"R2_test\"] = r2_score(y_test, y_test_pred)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"RMSE, RMAE, R2:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"reg_metrics = pd.DataFrame.from_dict(class_models, \"index\")[\n",
|
||
" [\"RMSE_train\", \"RMSE_test\", \"RMAE_test\", \"R2_test\"]\n",
|
||
"]\n",
|
||
"reg_metrics.sort_values(by=\"RMSE_test\").style.background_gradient(\n",
|
||
" cmap=\"viridis\", low=1, high=0.3, subset=[\"RMSE_train\", \"RMSE_test\"]\n",
|
||
").background_gradient(cmap=\"plasma\", low=0.3, high=1, subset=[\"RMAE_test\", \"R2_test\"])"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"Результаты графиками:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"# Создаем графики для всех моделей\n",
|
||
"for model_name, model_data in class_models.items():\n",
|
||
" print(f\"Model: {model_name}\")\n",
|
||
" y_pred = model_data[\"preds\"]\n",
|
||
" plt.figure(figsize=(10, 6))\n",
|
||
" plt.scatter(y_test, y_pred, alpha=0.5)\n",
|
||
" plt.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'k--', lw=2)\n",
|
||
" plt.xlabel('Фактический уровень глюкозы')\n",
|
||
" plt.ylabel('Прогнозируемый уровень глюкозы')\n",
|
||
" plt.title(f\"Model: {model_name}\")\n",
|
||
" plt.show()"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"На представленных графиках можно заметить, что модели в целом не демонстрируют высокого качества. Визуализация их предсказаний показывает сильное рассеивание вокруг идеальной линии y = x, что указывает на значительные отклонения предсказаний от фактических значений.\n",
|
||
"\n",
|
||
"Тем не менее ориентир, хоть возможно и не столь значительно, каждая из моделей превосходит по всем показателям. Особенно заметное улучшение в \n",
|
||
"R2, которая переходит из отрицательного значения в положительное, что говорит о том, что модели хотя бы частично объясняют дисперсию данных. \n",
|
||
"\n",
|
||
"Кроме того, можно сказать, что все модели имеет умеренную дисперсию и не сильно подвержены переобучению, потому что разница между RMSE на обучении и тесте незначительна.\n",
|
||
"\n",
|
||
"Итоговые выводы:\n",
|
||
"- Наиболее качественная модель: MLP, так как она показывает наименьшее значение RMSE и наибольшее значение R2, что указывает на лучшую точность и объяснение дисперсии целевой переменной.\n",
|
||
"\n",
|
||
"- Random Forest: Близок по производительности к MLP, с чуть большим RMSE, но является более устойчивой моделью с небольшими отклонениями между обучением и тестом.\n",
|
||
"\n",
|
||
"- KNN: Худшая модель, демонстрирующая наибольшие ошибки и низкое R2, что указывает на необходимость улучшения или использования другой модели для данной задачи."
|
||
]
|
||
}
|
||
],
|
||
"metadata": {
|
||
"kernelspec": {
|
||
"display_name": "venv",
|
||
"language": "python",
|
||
"name": "python3"
|
||
},
|
||
"language_info": {
|
||
"codemirror_mode": {
|
||
"name": "ipython",
|
||
"version": 3
|
||
},
|
||
"file_extension": ".py",
|
||
"mimetype": "text/x-python",
|
||
"name": "python",
|
||
"nbconvert_exporter": "python",
|
||
"pygments_lexer": "ipython3",
|
||
"version": "3.12.6"
|
||
}
|
||
},
|
||
"nbformat": 4,
|
||
"nbformat_minor": 2
|
||
}
|