1315 lines
120 KiB
Plaintext
1315 lines
120 KiB
Plaintext
{
|
||
"cells": [
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 52,
|
||
"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>work_year</th>\n",
|
||
" <th>experience_level</th>\n",
|
||
" <th>employment_type</th>\n",
|
||
" <th>job_title</th>\n",
|
||
" <th>salary</th>\n",
|
||
" <th>salary_currency</th>\n",
|
||
" <th>salary_in_usd</th>\n",
|
||
" <th>employee_residence</th>\n",
|
||
" <th>remote_ratio</th>\n",
|
||
" <th>company_location</th>\n",
|
||
" <th>company_size</th>\n",
|
||
" </tr>\n",
|
||
" </thead>\n",
|
||
" <tbody>\n",
|
||
" <tr>\n",
|
||
" <th>0</th>\n",
|
||
" <td>2023</td>\n",
|
||
" <td>SE</td>\n",
|
||
" <td>FT</td>\n",
|
||
" <td>Principal Data Scientist</td>\n",
|
||
" <td>80000</td>\n",
|
||
" <td>EUR</td>\n",
|
||
" <td>85847</td>\n",
|
||
" <td>ES</td>\n",
|
||
" <td>100</td>\n",
|
||
" <td>ES</td>\n",
|
||
" <td>L</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>1</th>\n",
|
||
" <td>2023</td>\n",
|
||
" <td>MI</td>\n",
|
||
" <td>CT</td>\n",
|
||
" <td>ML Engineer</td>\n",
|
||
" <td>30000</td>\n",
|
||
" <td>USD</td>\n",
|
||
" <td>30000</td>\n",
|
||
" <td>US</td>\n",
|
||
" <td>100</td>\n",
|
||
" <td>US</td>\n",
|
||
" <td>S</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>2</th>\n",
|
||
" <td>2023</td>\n",
|
||
" <td>MI</td>\n",
|
||
" <td>CT</td>\n",
|
||
" <td>ML Engineer</td>\n",
|
||
" <td>25500</td>\n",
|
||
" <td>USD</td>\n",
|
||
" <td>25500</td>\n",
|
||
" <td>US</td>\n",
|
||
" <td>100</td>\n",
|
||
" <td>US</td>\n",
|
||
" <td>S</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>3</th>\n",
|
||
" <td>2023</td>\n",
|
||
" <td>SE</td>\n",
|
||
" <td>FT</td>\n",
|
||
" <td>Data Scientist</td>\n",
|
||
" <td>175000</td>\n",
|
||
" <td>USD</td>\n",
|
||
" <td>175000</td>\n",
|
||
" <td>CA</td>\n",
|
||
" <td>100</td>\n",
|
||
" <td>CA</td>\n",
|
||
" <td>M</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>4</th>\n",
|
||
" <td>2023</td>\n",
|
||
" <td>SE</td>\n",
|
||
" <td>FT</td>\n",
|
||
" <td>Data Scientist</td>\n",
|
||
" <td>120000</td>\n",
|
||
" <td>USD</td>\n",
|
||
" <td>120000</td>\n",
|
||
" <td>CA</td>\n",
|
||
" <td>100</td>\n",
|
||
" <td>CA</td>\n",
|
||
" <td>M</td>\n",
|
||
" </tr>\n",
|
||
" </tbody>\n",
|
||
"</table>\n",
|
||
"</div>"
|
||
],
|
||
"text/plain": [
|
||
" work_year experience_level employment_type job_title \\\n",
|
||
"0 2023 SE FT Principal Data Scientist \n",
|
||
"1 2023 MI CT ML Engineer \n",
|
||
"2 2023 MI CT ML Engineer \n",
|
||
"3 2023 SE FT Data Scientist \n",
|
||
"4 2023 SE FT Data Scientist \n",
|
||
"\n",
|
||
" salary salary_currency salary_in_usd employee_residence remote_ratio \\\n",
|
||
"0 80000 EUR 85847 ES 100 \n",
|
||
"1 30000 USD 30000 US 100 \n",
|
||
"2 25500 USD 25500 US 100 \n",
|
||
"3 175000 USD 175000 CA 100 \n",
|
||
"4 120000 USD 120000 CA 100 \n",
|
||
"\n",
|
||
" company_location company_size \n",
|
||
"0 ES L \n",
|
||
"1 US S \n",
|
||
"2 US S \n",
|
||
"3 CA M \n",
|
||
"4 CA M "
|
||
]
|
||
},
|
||
"execution_count": 52,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"import pandas as pd\n",
|
||
"\n",
|
||
"df = pd.read_csv(\"..//static//csv//ds_salaries.csv\")\n",
|
||
"\n",
|
||
"df.head()"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"<h2>Бизнес-цели</h2>\n",
|
||
"Задача регрессии: Построить модель для прогноза зарплаты в USD используя атрибуты.<br>\n",
|
||
"Задача классификации: Определение уровня опыта сотрудника (experience_level) на основе других характеристик, таких как job_title, salary_in_usd, и employment_type."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"Проведем обработку данных и сделаем выборки"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 53,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Transformed feature shape (train): (2029, 151)\n",
|
||
"Transformed feature shape (test): (508, 151)\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"import numpy as np\n",
|
||
"from sklearn.model_selection import train_test_split\n",
|
||
"from sklearn.compose import ColumnTransformer\n",
|
||
"from sklearn.pipeline import Pipeline\n",
|
||
"from sklearn.impute import SimpleImputer\n",
|
||
"from sklearn.preprocessing import StandardScaler, OneHotEncoder\n",
|
||
"\n",
|
||
"# Удаление выбросов из столбца `salary_in_usd` с использованием IQR\n",
|
||
"Q1 = df['salary_in_usd'].quantile(0.25)\n",
|
||
"Q3 = df['salary_in_usd'].quantile(0.75)\n",
|
||
"IQR = Q3 - Q1\n",
|
||
"df = df[(df['salary_in_usd'] >= Q1 - 1.5 * IQR) & (df['salary_in_usd'] <= Q3 + 1.5 * IQR)]\n",
|
||
"\n",
|
||
"# Преобразование категориальных данных в числовые (если потребуется)\n",
|
||
"if 'remote_ratio' in df.columns:\n",
|
||
" df['remote_ratio'] = df['remote_ratio'].astype(int)\n",
|
||
"\n",
|
||
"# Удаление дубликатов\n",
|
||
"df.drop_duplicates(inplace=True)\n",
|
||
"\n",
|
||
"# Определение целевой переменной и признаков\n",
|
||
"X = df.drop(columns=['salary_in_usd', 'salary_currency', 'job_title']) # Признаки\n",
|
||
"y = df['salary_in_usd'] # Целевая переменная для регрессии\n",
|
||
"\n",
|
||
"# Определение числовых и категориальных признаков\n",
|
||
"numeric_features = ['work_year', 'remote_ratio']\n",
|
||
"categorical_features = ['experience_level', 'employment_type', \n",
|
||
" 'employee_residence', 'company_location', 'company_size']\n",
|
||
"\n",
|
||
"# Обработка числовых данных\n",
|
||
"numeric_transformer = Pipeline(steps=[\n",
|
||
" ('imputer', SimpleImputer(strategy='median')), # Заполнение пропусков медианой\n",
|
||
" ('scaler', StandardScaler()) # Нормализация данных\n",
|
||
"])\n",
|
||
"\n",
|
||
"# Обработка категориальных данных\n",
|
||
"categorical_transformer = Pipeline(steps=[\n",
|
||
" ('imputer', SimpleImputer(strategy='most_frequent')), # Заполнение пропусков модой\n",
|
||
" ('onehot', OneHotEncoder(handle_unknown='ignore')) # Преобразование в One-Hot Encoding\n",
|
||
"])\n",
|
||
"\n",
|
||
"# Комбинированный трансформер\n",
|
||
"preprocessor = ColumnTransformer(\n",
|
||
" transformers=[\n",
|
||
" ('num', numeric_transformer, numeric_features), # Применяем числовую обработку\n",
|
||
" ('cat', categorical_transformer, categorical_features) # Применяем категориальную обработку\n",
|
||
" ]\n",
|
||
")\n",
|
||
"\n",
|
||
"# Разделение данных на обучающую и тестовую выборки\n",
|
||
"X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)\n",
|
||
"\n",
|
||
"# Применение пайплайна\n",
|
||
"X_train_transformed = preprocessor.fit_transform(X_train)\n",
|
||
"X_test_transformed = preprocessor.transform(X_test)\n",
|
||
"\n",
|
||
"# Проверка результата трансформации\n",
|
||
"print(f\"Transformed feature shape (train): {X_train_transformed.shape}\")\n",
|
||
"print(f\"Transformed feature shape (test): {X_test_transformed.shape}\")\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"Выведим результаты"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 54,
|
||
"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>work_year</th>\n",
|
||
" <th>remote_ratio</th>\n",
|
||
" <th>experience_level_EN</th>\n",
|
||
" <th>experience_level_EX</th>\n",
|
||
" <th>experience_level_MI</th>\n",
|
||
" <th>experience_level_SE</th>\n",
|
||
" <th>employment_type_CT</th>\n",
|
||
" <th>employment_type_FL</th>\n",
|
||
" <th>employment_type_FT</th>\n",
|
||
" <th>employment_type_PT</th>\n",
|
||
" <th>...</th>\n",
|
||
" <th>company_location_SI</th>\n",
|
||
" <th>company_location_SK</th>\n",
|
||
" <th>company_location_TH</th>\n",
|
||
" <th>company_location_TR</th>\n",
|
||
" <th>company_location_UA</th>\n",
|
||
" <th>company_location_US</th>\n",
|
||
" <th>company_location_VN</th>\n",
|
||
" <th>company_size_L</th>\n",
|
||
" <th>company_size_M</th>\n",
|
||
" <th>company_size_S</th>\n",
|
||
" </tr>\n",
|
||
" </thead>\n",
|
||
" <tbody>\n",
|
||
" <tr>\n",
|
||
" <th>0</th>\n",
|
||
" <td>-1.747172</td>\n",
|
||
" <td>1.016983</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>0.0</td>\n",
|
||
" <td>...</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>0.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>1</th>\n",
|
||
" <td>-1.747172</td>\n",
|
||
" <td>1.016983</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>0.0</td>\n",
|
||
" <td>...</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.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>2</th>\n",
|
||
" <td>0.943539</td>\n",
|
||
" <td>-1.057887</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>0.0</td>\n",
|
||
" <td>...</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>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>3</th>\n",
|
||
" <td>-0.401816</td>\n",
|
||
" <td>1.016983</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.0</td>\n",
|
||
" <td>...</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>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>4</th>\n",
|
||
" <td>-0.401816</td>\n",
|
||
" <td>-0.020452</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.0</td>\n",
|
||
" <td>...</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>0.0</td>\n",
|
||
" <td>1.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" <td>0.0</td>\n",
|
||
" </tr>\n",
|
||
" </tbody>\n",
|
||
"</table>\n",
|
||
"<p>5 rows × 151 columns</p>\n",
|
||
"</div>"
|
||
],
|
||
"text/plain": [
|
||
" work_year remote_ratio experience_level_EN experience_level_EX \\\n",
|
||
"0 -1.747172 1.016983 0.0 0.0 \n",
|
||
"1 -1.747172 1.016983 0.0 0.0 \n",
|
||
"2 0.943539 -1.057887 0.0 0.0 \n",
|
||
"3 -0.401816 1.016983 0.0 0.0 \n",
|
||
"4 -0.401816 -0.020452 0.0 0.0 \n",
|
||
"\n",
|
||
" experience_level_MI experience_level_SE employment_type_CT \\\n",
|
||
"0 0.0 1.0 0.0 \n",
|
||
"1 0.0 1.0 0.0 \n",
|
||
"2 0.0 1.0 0.0 \n",
|
||
"3 1.0 0.0 0.0 \n",
|
||
"4 1.0 0.0 0.0 \n",
|
||
"\n",
|
||
" employment_type_FL employment_type_FT employment_type_PT ... \\\n",
|
||
"0 0.0 1.0 0.0 ... \n",
|
||
"1 0.0 1.0 0.0 ... \n",
|
||
"2 0.0 1.0 0.0 ... \n",
|
||
"3 0.0 1.0 0.0 ... \n",
|
||
"4 0.0 1.0 0.0 ... \n",
|
||
"\n",
|
||
" company_location_SI company_location_SK company_location_TH \\\n",
|
||
"0 0.0 0.0 0.0 \n",
|
||
"1 0.0 0.0 0.0 \n",
|
||
"2 0.0 0.0 0.0 \n",
|
||
"3 0.0 0.0 0.0 \n",
|
||
"4 0.0 0.0 0.0 \n",
|
||
"\n",
|
||
" company_location_TR company_location_UA company_location_US \\\n",
|
||
"0 0.0 0.0 0.0 \n",
|
||
"1 0.0 0.0 1.0 \n",
|
||
"2 0.0 0.0 1.0 \n",
|
||
"3 0.0 0.0 1.0 \n",
|
||
"4 0.0 0.0 0.0 \n",
|
||
"\n",
|
||
" company_location_VN company_size_L company_size_M company_size_S \n",
|
||
"0 0.0 1.0 0.0 0.0 \n",
|
||
"1 0.0 1.0 0.0 0.0 \n",
|
||
"2 0.0 0.0 1.0 0.0 \n",
|
||
"3 0.0 0.0 1.0 0.0 \n",
|
||
"4 0.0 1.0 0.0 0.0 \n",
|
||
"\n",
|
||
"[5 rows x 151 columns]"
|
||
]
|
||
},
|
||
"execution_count": 54,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"# Получим имена категориальных признаков после OneHotEncoder\n",
|
||
"categorical_feature_names = preprocessor.named_transformers_['cat']['onehot'].get_feature_names_out(categorical_features)\n",
|
||
"\n",
|
||
"# Объединим их с именами числовых признаков\n",
|
||
"feature_names = list(numeric_features) + list(categorical_feature_names)\n",
|
||
"\n",
|
||
"# Создадим DataFrame для преобразованных данных\n",
|
||
"X_train_transformed_df = pd.DataFrame(X_train_transformed.toarray() if hasattr(X_train_transformed, 'toarray') else X_train_transformed, columns=feature_names)\n",
|
||
"\n",
|
||
"# Выведем первые 5 строк обработанного набора данных\n",
|
||
"X_train_transformed_df.head()"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"Обучим три модели"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 55,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Training LinearRegression...\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"c:\\Users\\salih\\OneDrive\\Рабочий стол\\3 курас\\МИИ\\laba1\\AIM-PIbd-31-Yaruskin-S-A\\aimenv\\Lib\\site-packages\\sklearn\\model_selection\\_search.py:320: UserWarning: The total space of parameters 1 is smaller than n_iter=20. Running 1 iterations. For exhaustive searches, use GridSearchCV.\n",
|
||
" warnings.warn(\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Training RandomForestRegressor...\n",
|
||
"Training GradientBoostingRegressor...\n",
|
||
"\n",
|
||
"Model: LinearRegression\n",
|
||
"Best Params: {}\n",
|
||
"MAE: 35903.74761235383\n",
|
||
"RMSE: 45746.92374132039\n",
|
||
"R2: 0.41681042958060477\n",
|
||
"\n",
|
||
"Model: RandomForestRegressor\n",
|
||
"Best Params: {'model__n_estimators': 100, 'model__min_samples_split': 10, 'model__max_depth': 20}\n",
|
||
"MAE: 35382.49447920311\n",
|
||
"RMSE: 45711.49865435396\n",
|
||
"R2: 0.41771328994747514\n",
|
||
"\n",
|
||
"Model: GradientBoostingRegressor\n",
|
||
"Best Params: {'model__n_estimators': 50, 'model__max_depth': 5, 'model__learning_rate': 0.2}\n",
|
||
"MAE: 35404.55042553757\n",
|
||
"RMSE: 45669.354449671955\n",
|
||
"R2: 0.41878648590699374\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"import numpy as np\n",
|
||
"from sklearn.linear_model import LinearRegression\n",
|
||
"from sklearn.ensemble import RandomForestRegressor\n",
|
||
"from sklearn.ensemble import GradientBoostingRegressor\n",
|
||
"from sklearn.model_selection import RandomizedSearchCV\n",
|
||
"from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score\n",
|
||
"from sklearn.pipeline import Pipeline\n",
|
||
"from sklearn.compose import ColumnTransformer\n",
|
||
"\n",
|
||
"# Задание случайного состояния\n",
|
||
"random_state = 42\n",
|
||
"\n",
|
||
"# Модели и параметры\n",
|
||
"models_regression = {\n",
|
||
" \"LinearRegression\": LinearRegression(),\n",
|
||
" \"RandomForestRegressor\": RandomForestRegressor(random_state=random_state),\n",
|
||
" \"GradientBoostingRegressor\": GradientBoostingRegressor(random_state=random_state)\n",
|
||
"}\n",
|
||
"\n",
|
||
"param_grids_regression = {\n",
|
||
" \"LinearRegression\": {},\n",
|
||
" \"RandomForestRegressor\": {\n",
|
||
" 'model__n_estimators': [50, 100, 200],\n",
|
||
" 'model__max_depth': [None, 10, 20],\n",
|
||
" 'model__min_samples_split': [2, 5, 10]\n",
|
||
" },\n",
|
||
" \"GradientBoostingRegressor\": {\n",
|
||
" 'model__n_estimators': [50, 100, 200],\n",
|
||
" 'model__learning_rate': [0.01, 0.1, 0.2],\n",
|
||
" 'model__max_depth': [3, 5, 10]\n",
|
||
" }\n",
|
||
"}\n",
|
||
"\n",
|
||
"# Результаты\n",
|
||
"results_regression = {}\n",
|
||
"\n",
|
||
"# Перебор моделей\n",
|
||
"for name, model in models_regression.items():\n",
|
||
" print(f\"Training {name}...\")\n",
|
||
" \n",
|
||
" # Создание пайплайна\n",
|
||
" pipeline = Pipeline(steps=[\n",
|
||
" ('preprocessor', preprocessor), # Используем уже созданный preprocessor\n",
|
||
" ('model', model)\n",
|
||
" ])\n",
|
||
" \n",
|
||
" # Определение параметров для RandomizedSearchCV\n",
|
||
" param_grid = param_grids_regression[name]\n",
|
||
" search = RandomizedSearchCV(pipeline, param_distributions=param_grid, \n",
|
||
" cv=5, scoring='neg_mean_absolute_error', \n",
|
||
" n_jobs=-1, random_state=random_state, n_iter=20)\n",
|
||
" search.fit(X_train, y_train)\n",
|
||
" \n",
|
||
" # Лучшая модель\n",
|
||
" best_model = search.best_estimator_\n",
|
||
" y_pred = best_model.predict(X_test)\n",
|
||
" \n",
|
||
" # Метрики\n",
|
||
" mae = mean_absolute_error(y_test, y_pred)\n",
|
||
" rmse = np.sqrt(mean_squared_error(y_test, y_pred))\n",
|
||
" r2 = r2_score(y_test, y_pred)\n",
|
||
" \n",
|
||
" # Сохранение результатов\n",
|
||
" results_regression[name] = {\n",
|
||
" \"Best Params\": search.best_params_,\n",
|
||
" \"MAE\": mae,\n",
|
||
" \"RMSE\": rmse,\n",
|
||
" \"R2\": r2\n",
|
||
" }\n",
|
||
"\n",
|
||
"# Печать результатов\n",
|
||
"for name, metrics in results_regression.items():\n",
|
||
" print(f\"\\nModel: {name}\")\n",
|
||
" for metric, value in metrics.items():\n",
|
||
" print(f\"{metric}: {value}\")\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 56,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/html": [
|
||
"<style type=\"text/css\">\n",
|
||
"#T_05579_row0_col0 {\n",
|
||
" background-color: #25858e;\n",
|
||
" color: #f1f1f1;\n",
|
||
"}\n",
|
||
"#T_05579_row0_col1, #T_05579_row1_col0 {\n",
|
||
" background-color: #26818e;\n",
|
||
" color: #f1f1f1;\n",
|
||
"}\n",
|
||
"#T_05579_row0_col2 {\n",
|
||
" background-color: #da5a6a;\n",
|
||
" color: #f1f1f1;\n",
|
||
"}\n",
|
||
"#T_05579_row1_col1 {\n",
|
||
" background-color: #37b878;\n",
|
||
" color: #f1f1f1;\n",
|
||
"}\n",
|
||
"#T_05579_row1_col2 {\n",
|
||
" background-color: #9a169f;\n",
|
||
" color: #f1f1f1;\n",
|
||
"}\n",
|
||
"#T_05579_row2_col0, #T_05579_row2_col1 {\n",
|
||
" background-color: #a8db34;\n",
|
||
" color: #000000;\n",
|
||
"}\n",
|
||
"#T_05579_row2_col2 {\n",
|
||
" background-color: #4e02a2;\n",
|
||
" color: #f1f1f1;\n",
|
||
"}\n",
|
||
"</style>\n",
|
||
"<table id=\"T_05579\">\n",
|
||
" <thead>\n",
|
||
" <tr>\n",
|
||
" <th class=\"blank level0\" > </th>\n",
|
||
" <th id=\"T_05579_level0_col0\" class=\"col_heading level0 col0\" >MAE</th>\n",
|
||
" <th id=\"T_05579_level0_col1\" class=\"col_heading level0 col1\" >RMSE</th>\n",
|
||
" <th id=\"T_05579_level0_col2\" class=\"col_heading level0 col2\" >R2</th>\n",
|
||
" </tr>\n",
|
||
" </thead>\n",
|
||
" <tbody>\n",
|
||
" <tr>\n",
|
||
" <th id=\"T_05579_level0_row0\" class=\"row_heading level0 row0\" >GradientBoostingRegressor</th>\n",
|
||
" <td id=\"T_05579_row0_col0\" class=\"data row0 col0\" >35404.550426</td>\n",
|
||
" <td id=\"T_05579_row0_col1\" class=\"data row0 col1\" >45669.354450</td>\n",
|
||
" <td id=\"T_05579_row0_col2\" class=\"data row0 col2\" >0.418786</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th id=\"T_05579_level0_row1\" class=\"row_heading level0 row1\" >RandomForestRegressor</th>\n",
|
||
" <td id=\"T_05579_row1_col0\" class=\"data row1 col0\" >35382.494479</td>\n",
|
||
" <td id=\"T_05579_row1_col1\" class=\"data row1 col1\" >45711.498654</td>\n",
|
||
" <td id=\"T_05579_row1_col2\" class=\"data row1 col2\" >0.417713</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th id=\"T_05579_level0_row2\" class=\"row_heading level0 row2\" >LinearRegression</th>\n",
|
||
" <td id=\"T_05579_row2_col0\" class=\"data row2 col0\" >35903.747612</td>\n",
|
||
" <td id=\"T_05579_row2_col1\" class=\"data row2 col1\" >45746.923741</td>\n",
|
||
" <td id=\"T_05579_row2_col2\" class=\"data row2 col2\" >0.416810</td>\n",
|
||
" </tr>\n",
|
||
" </tbody>\n",
|
||
"</table>\n"
|
||
],
|
||
"text/plain": [
|
||
"<pandas.io.formats.style.Styler at 0x27c0be5fc50>"
|
||
]
|
||
},
|
||
"execution_count": 56,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"# Формирование таблицы метрик из результатов регрессионных моделей\n",
|
||
"reg_metrics = pd.DataFrame.from_dict(results_regression, orient=\"index\")[\n",
|
||
" [\"MAE\", \"RMSE\", \"R2\"]\n",
|
||
"]\n",
|
||
"\n",
|
||
"# Визуализация результатов с помощью стилизации\n",
|
||
"styled_metrics = (\n",
|
||
" reg_metrics.sort_values(by=\"RMSE\")\n",
|
||
" .style.background_gradient(cmap=\"viridis\", low=1, high=0.3, subset=[\"RMSE\", \"MAE\"])\n",
|
||
" .background_gradient(cmap=\"plasma\", low=0.3, high=1, subset=[\"R2\"])\n",
|
||
")\n",
|
||
"\n",
|
||
"# Отобразим таблицу\n",
|
||
"styled_metrics"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"Чтото слабоватые модели получились. Даже 50% нет, нужно попробовать улучшить данные."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 57,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Transformed feature shape (train): (2029, 153)\n",
|
||
"Transformed feature shape (test): (508, 153)\n",
|
||
"Training LinearRegression...\n",
|
||
"Training RandomForestRegressor...\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"c:\\Users\\salih\\OneDrive\\Рабочий стол\\3 курас\\МИИ\\laba1\\AIM-PIbd-31-Yaruskin-S-A\\aimenv\\Lib\\site-packages\\sklearn\\model_selection\\_search.py:320: UserWarning: The total space of parameters 1 is smaller than n_iter=20. Running 1 iterations. For exhaustive searches, use GridSearchCV.\n",
|
||
" warnings.warn(\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Training GradientBoostingRegressor...\n",
|
||
"\n",
|
||
"Model: LinearRegression\n",
|
||
"Best Params: {}\n",
|
||
"MAE: 35923.393167146765\n",
|
||
"RMSE: 45787.2465103007\n",
|
||
"R2: 0.41578189344376837\n",
|
||
"\n",
|
||
"Model: RandomForestRegressor\n",
|
||
"Best Params: {'model__n_estimators': 100, 'model__min_samples_split': 10, 'model__max_depth': 20}\n",
|
||
"MAE: 35428.00841155441\n",
|
||
"RMSE: 45772.13311276274\n",
|
||
"R2: 0.41616750576805106\n",
|
||
"\n",
|
||
"Model: GradientBoostingRegressor\n",
|
||
"Best Params: {'model__n_estimators': 100, 'model__max_depth': 3, 'model__learning_rate': 0.1}\n",
|
||
"MAE: 35575.964157916314\n",
|
||
"RMSE: 45645.593157690266\n",
|
||
"R2: 0.41939112731165484\n"
|
||
]
|
||
},
|
||
{
|
||
"data": {
|
||
"text/html": [
|
||
"<style type=\"text/css\">\n",
|
||
"#T_baae7_row0_col0 {\n",
|
||
" background-color: #1fa088;\n",
|
||
" color: #f1f1f1;\n",
|
||
"}\n",
|
||
"#T_baae7_row0_col1, #T_baae7_row1_col0 {\n",
|
||
" background-color: #26818e;\n",
|
||
" color: #f1f1f1;\n",
|
||
"}\n",
|
||
"#T_baae7_row0_col2 {\n",
|
||
" background-color: #da5a6a;\n",
|
||
" color: #f1f1f1;\n",
|
||
"}\n",
|
||
"#T_baae7_row1_col1 {\n",
|
||
" background-color: #89d548;\n",
|
||
" color: #000000;\n",
|
||
"}\n",
|
||
"#T_baae7_row1_col2 {\n",
|
||
" background-color: #6100a7;\n",
|
||
" color: #f1f1f1;\n",
|
||
"}\n",
|
||
"#T_baae7_row2_col0, #T_baae7_row2_col1 {\n",
|
||
" background-color: #a8db34;\n",
|
||
" color: #000000;\n",
|
||
"}\n",
|
||
"#T_baae7_row2_col2 {\n",
|
||
" background-color: #4e02a2;\n",
|
||
" color: #f1f1f1;\n",
|
||
"}\n",
|
||
"</style>\n",
|
||
"<table id=\"T_baae7\">\n",
|
||
" <thead>\n",
|
||
" <tr>\n",
|
||
" <th class=\"blank level0\" > </th>\n",
|
||
" <th id=\"T_baae7_level0_col0\" class=\"col_heading level0 col0\" >MAE</th>\n",
|
||
" <th id=\"T_baae7_level0_col1\" class=\"col_heading level0 col1\" >RMSE</th>\n",
|
||
" <th id=\"T_baae7_level0_col2\" class=\"col_heading level0 col2\" >R2</th>\n",
|
||
" </tr>\n",
|
||
" </thead>\n",
|
||
" <tbody>\n",
|
||
" <tr>\n",
|
||
" <th id=\"T_baae7_level0_row0\" class=\"row_heading level0 row0\" >GradientBoostingRegressor</th>\n",
|
||
" <td id=\"T_baae7_row0_col0\" class=\"data row0 col0\" >35575.964158</td>\n",
|
||
" <td id=\"T_baae7_row0_col1\" class=\"data row0 col1\" >45645.593158</td>\n",
|
||
" <td id=\"T_baae7_row0_col2\" class=\"data row0 col2\" >0.419391</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th id=\"T_baae7_level0_row1\" class=\"row_heading level0 row1\" >RandomForestRegressor</th>\n",
|
||
" <td id=\"T_baae7_row1_col0\" class=\"data row1 col0\" >35428.008412</td>\n",
|
||
" <td id=\"T_baae7_row1_col1\" class=\"data row1 col1\" >45772.133113</td>\n",
|
||
" <td id=\"T_baae7_row1_col2\" class=\"data row1 col2\" >0.416168</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th id=\"T_baae7_level0_row2\" class=\"row_heading level0 row2\" >LinearRegression</th>\n",
|
||
" <td id=\"T_baae7_row2_col0\" class=\"data row2 col0\" >35923.393167</td>\n",
|
||
" <td id=\"T_baae7_row2_col1\" class=\"data row2 col1\" >45787.246510</td>\n",
|
||
" <td id=\"T_baae7_row2_col2\" class=\"data row2 col2\" >0.415782</td>\n",
|
||
" </tr>\n",
|
||
" </tbody>\n",
|
||
"</table>\n"
|
||
],
|
||
"text/plain": [
|
||
"<pandas.io.formats.style.Styler at 0x27c0bec9850>"
|
||
]
|
||
},
|
||
"execution_count": 57,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"# Функция для приведения выбросов к среднему значению\n",
|
||
"def handle_outliers(df, column):\n",
|
||
" Q1 = df[column].quantile(0.25)\n",
|
||
" Q3 = df[column].quantile(0.75)\n",
|
||
" IQR = Q3 - Q1\n",
|
||
" lower_bound = Q1 - 1.5 * IQR\n",
|
||
" upper_bound = Q3 + 1.5 * IQR\n",
|
||
" \n",
|
||
" mean_value = df[column].mean()\n",
|
||
" df[column] = np.where((df[column] < lower_bound) | (df[column] > upper_bound), mean_value, df[column])\n",
|
||
" return df\n",
|
||
"\n",
|
||
"# Приведение выбросов в столбце `salary_in_usd` к среднему значению\n",
|
||
"df = handle_outliers(df, 'salary_in_usd')\n",
|
||
"\n",
|
||
"# Преобразование категориальных данных в строковые для корректной обработки\n",
|
||
"if 'remote_ratio' in df.columns:\n",
|
||
" df['remote_ratio'] = df['remote_ratio'].astype(str)\n",
|
||
"\n",
|
||
"# Удаление дубликатов\n",
|
||
"df.drop_duplicates(inplace=True)\n",
|
||
"\n",
|
||
"# Определение целевой переменной и признаков\n",
|
||
"X = df.drop(columns=['salary_in_usd', 'salary_currency', 'job_title']) # Признаки\n",
|
||
"y = df['salary_in_usd'] # Целевая переменная для регрессии\n",
|
||
"\n",
|
||
"# Определение числовых и категориальных признаков\n",
|
||
"numeric_features = ['work_year'] # Убрали 'remote_ratio', так как это категориальный признак\n",
|
||
"categorical_features = ['experience_level', 'employment_type', \n",
|
||
" 'employee_residence', 'company_location', 'company_size', 'remote_ratio']\n",
|
||
"\n",
|
||
"# Обработка числовых данных\n",
|
||
"numeric_transformer = Pipeline(steps=[\n",
|
||
" ('imputer', SimpleImputer(strategy='median')), # Заполнение пропусков медианой\n",
|
||
" ('scaler', StandardScaler()) # Нормализация данных\n",
|
||
"])\n",
|
||
"\n",
|
||
"# Обработка категориальных данных\n",
|
||
"categorical_transformer = Pipeline(steps=[\n",
|
||
" ('imputer', SimpleImputer(strategy='most_frequent')), # Заполнение пропусков модой\n",
|
||
" ('onehot', OneHotEncoder(handle_unknown='ignore')) # Преобразование в One-Hot Encoding\n",
|
||
"])\n",
|
||
"\n",
|
||
"# Комбинированный трансформер\n",
|
||
"preprocessor = ColumnTransformer(\n",
|
||
" transformers=[\n",
|
||
" ('num', numeric_transformer, numeric_features), # Применяем числовую обработку\n",
|
||
" ('cat', categorical_transformer, categorical_features) # Применяем категориальную обработку\n",
|
||
" ]\n",
|
||
")\n",
|
||
"\n",
|
||
"# Разделение данных на обучающую и тестовую выборки\n",
|
||
"X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)\n",
|
||
"\n",
|
||
"# Применение пайплайна\n",
|
||
"X_train_transformed = preprocessor.fit_transform(X_train)\n",
|
||
"X_test_transformed = preprocessor.transform(X_test)\n",
|
||
"\n",
|
||
"# Проверка результата трансформации\n",
|
||
"print(f\"Transformed feature shape (train): {X_train_transformed.shape}\")\n",
|
||
"print(f\"Transformed feature shape (test): {X_test_transformed.shape}\")\n",
|
||
"\n",
|
||
"# Определение моделей и их параметров\n",
|
||
"models = {\n",
|
||
" \"LinearRegression\": LinearRegression(),\n",
|
||
" \"RandomForestRegressor\": RandomForestRegressor(random_state=42),\n",
|
||
" \"GradientBoostingRegressor\": GradientBoostingRegressor(random_state=42)\n",
|
||
"}\n",
|
||
"\n",
|
||
"param_grids = {\n",
|
||
" \"LinearRegression\": {},\n",
|
||
" \"RandomForestRegressor\": {\n",
|
||
" 'model__n_estimators': [100, 200, 300],\n",
|
||
" 'model__max_depth': [10, 20, None],\n",
|
||
" 'model__min_samples_split': [2, 5, 10]\n",
|
||
" },\n",
|
||
" \"GradientBoostingRegressor\": {\n",
|
||
" 'model__n_estimators': [100, 200, 300],\n",
|
||
" 'model__learning_rate': [0.01, 0.1, 0.2],\n",
|
||
" 'model__max_depth': [3, 5, 7]\n",
|
||
" }\n",
|
||
"}\n",
|
||
"\n",
|
||
"# Результаты\n",
|
||
"results = {}\n",
|
||
"\n",
|
||
"# Обучение моделей с подбором гиперпараметров\n",
|
||
"for name, model in models.items():\n",
|
||
" print(f\"Training {name}...\")\n",
|
||
" pipeline = Pipeline(steps=[\n",
|
||
" ('preprocessor', preprocessor),\n",
|
||
" ('model', model)\n",
|
||
" ])\n",
|
||
" param_grid = param_grids[name]\n",
|
||
" search = RandomizedSearchCV(pipeline, param_distributions=param_grid, cv=5, \n",
|
||
" scoring='neg_mean_absolute_error', n_jobs=-1, \n",
|
||
" random_state=42, n_iter=20)\n",
|
||
" search.fit(X_train, y_train)\n",
|
||
" \n",
|
||
" # Лучшая модель\n",
|
||
" best_model = search.best_estimator_\n",
|
||
" y_pred = best_model.predict(X_test)\n",
|
||
" \n",
|
||
" # Метрики\n",
|
||
" mae = mean_absolute_error(y_test, y_pred)\n",
|
||
" rmse = np.sqrt(mean_squared_error(y_test, y_pred))\n",
|
||
" r2 = r2_score(y_test, y_pred)\n",
|
||
" \n",
|
||
" # Сохранение результатов\n",
|
||
" results[name] = {\n",
|
||
" \"Best Params\": search.best_params_,\n",
|
||
" \"MAE\": mae,\n",
|
||
" \"RMSE\": rmse,\n",
|
||
" \"R2\": r2\n",
|
||
" }\n",
|
||
"\n",
|
||
"# Печать результатов\n",
|
||
"for name, metrics in results.items():\n",
|
||
" print(f\"\\nModel: {name}\")\n",
|
||
" for metric, value in metrics.items():\n",
|
||
" print(f\"{metric}: {value}\")\n",
|
||
"\n",
|
||
"# Формирование таблицы метрик из результатов регрессионных моделей\n",
|
||
"reg_metrics = pd.DataFrame.from_dict(results, orient=\"index\")[\n",
|
||
" [\"MAE\", \"RMSE\", \"R2\"]\n",
|
||
"]\n",
|
||
"\n",
|
||
"# Визуализация результатов с помощью стилизации\n",
|
||
"styled_metrics = (\n",
|
||
" reg_metrics.sort_values(by=\"RMSE\")\n",
|
||
" .style.background_gradient(cmap=\"viridis\", low=1, high=0.3, subset=[\"RMSE\", \"MAE\"])\n",
|
||
" .background_gradient(cmap=\"plasma\", low=0.3, high=1, subset=[\"R2\"])\n",
|
||
")\n",
|
||
"\n",
|
||
"# Отобразим таблицу\n",
|
||
"styled_metrics"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"Переписал не много код, стало чуть лучше, но не намного. Думаю для моей первой работы подойдет"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"<h2>Приступим к задаче классификации</h2>"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 58,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Training LogisticRegression...\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"c:\\Users\\salih\\OneDrive\\Рабочий стол\\3 курас\\МИИ\\laba1\\AIM-PIbd-31-Yaruskin-S-A\\aimenv\\Lib\\site-packages\\sklearn\\model_selection\\_search.py:320: UserWarning: The total space of parameters 3 is smaller than n_iter=10. Running 3 iterations. For exhaustive searches, use GridSearchCV.\n",
|
||
" warnings.warn(\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Training RandomForestClassifier...\n",
|
||
"Training KNN...\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"c:\\Users\\salih\\OneDrive\\Рабочий стол\\3 курас\\МИИ\\laba1\\AIM-PIbd-31-Yaruskin-S-A\\aimenv\\Lib\\site-packages\\sklearn\\model_selection\\_search.py:320: UserWarning: The total space of parameters 8 is smaller than n_iter=10. Running 8 iterations. For exhaustive searches, use GridSearchCV.\n",
|
||
" warnings.warn(\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"\n",
|
||
"Model: LogisticRegression\n",
|
||
"Best Params: {'model__C': 0.1}\n",
|
||
"Accuracy: 1.0\n",
|
||
"F1 Score: 1.0\n",
|
||
"Confusion_matrix: [[ 50 0 0 0]\n",
|
||
" [ 0 129 0 0]\n",
|
||
" [ 0 0 316 0]\n",
|
||
" [ 0 0 0 13]]\n",
|
||
"\n",
|
||
"Model: RandomForestClassifier\n",
|
||
"Best Params: {'model__n_estimators': 300, 'model__max_features': None, 'model__max_depth': 15, 'model__criterion': 'entropy'}\n",
|
||
"Accuracy: 1.0\n",
|
||
"F1 Score: 1.0\n",
|
||
"Confusion_matrix: [[ 50 0 0 0]\n",
|
||
" [ 0 129 0 0]\n",
|
||
" [ 0 0 316 0]\n",
|
||
" [ 0 0 0 13]]\n",
|
||
"\n",
|
||
"Model: KNN\n",
|
||
"Best Params: {'model__weights': 'distance', 'model__n_neighbors': 9}\n",
|
||
"Accuracy: 0.9940944881889764\n",
|
||
"F1 Score: 0.9641274132899506\n",
|
||
"Confusion_matrix: [[ 50 0 0 0]\n",
|
||
" [ 0 129 0 0]\n",
|
||
" [ 0 0 316 0]\n",
|
||
" [ 1 0 2 10]]\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"from sklearn.ensemble import RandomForestClassifier\n",
|
||
"from sklearn.linear_model import LogisticRegression\n",
|
||
"from sklearn.neighbors import KNeighborsClassifier\n",
|
||
"from sklearn.metrics import accuracy_score, confusion_matrix, f1_score\n",
|
||
"\n",
|
||
"# Удалить строки с пропусками в experience_level\n",
|
||
"df = df.dropna(subset=['experience_level'])\n",
|
||
"\n",
|
||
"# Пересоздать y_class\n",
|
||
"y_class = df['experience_level'].map({'EN': 0, 'MI': 1, 'SE': 2, 'EX': 3})\n",
|
||
"\n",
|
||
"# Повторное разделение данных\n",
|
||
"X_train_clf, X_test_clf, y_train_clf, y_test_clf = train_test_split(X, y_class, test_size=0.2, random_state=42)\n",
|
||
"\n",
|
||
"# Определение моделей и их гиперпараметров\n",
|
||
"models_classification = {\n",
|
||
" \"LogisticRegression\": LogisticRegression(max_iter=1000),\n",
|
||
" \"RandomForestClassifier\": RandomForestClassifier(random_state=42),\n",
|
||
" \"KNN\": KNeighborsClassifier()\n",
|
||
"}\n",
|
||
"\n",
|
||
"param_grids_classification = {\n",
|
||
" \"LogisticRegression\": {\n",
|
||
" 'model__C': [0.1, 1, 10]\n",
|
||
" },\n",
|
||
" \"RandomForestClassifier\": {\n",
|
||
" \"model__n_estimators\": [100, 200, 300],\n",
|
||
" \"model__max_features\": [\"sqrt\", \"log2\", None],\n",
|
||
" \"model__max_depth\": [5, 10, 15, None],\n",
|
||
" \"model__criterion\": [\"gini\", \"entropy\"]\n",
|
||
" },\n",
|
||
" \"KNN\": {\n",
|
||
" 'model__n_neighbors': [3, 5, 7, 9],\n",
|
||
" 'model__weights': ['uniform', 'distance']\n",
|
||
" }\n",
|
||
"}\n",
|
||
"\n",
|
||
"# Результаты\n",
|
||
"results_classification = {}\n",
|
||
"\n",
|
||
"# Перебор моделей\n",
|
||
"for name, model in models_classification.items():\n",
|
||
" print(f\"Training {name}...\")\n",
|
||
" pipeline = Pipeline(steps=[\n",
|
||
" ('preprocessor', preprocessor),\n",
|
||
" ('model', model)\n",
|
||
" ])\n",
|
||
" param_grid = param_grids_classification[name]\n",
|
||
" grid_search = RandomizedSearchCV(pipeline, param_distributions=param_grid, cv=5, scoring='f1_macro', n_jobs=-1, random_state=42)\n",
|
||
" grid_search.fit(X_train_clf, y_train_clf)\n",
|
||
"\n",
|
||
" # Лучшая модель\n",
|
||
" best_model = grid_search.best_estimator_\n",
|
||
" y_pred = best_model.predict(X_test_clf)\n",
|
||
"\n",
|
||
" # Метрики\n",
|
||
" acc = accuracy_score(y_test_clf, y_pred)\n",
|
||
" f1 = f1_score(y_test_clf, y_pred, average='macro')\n",
|
||
"\n",
|
||
" # Вычисление матрицы ошибок\n",
|
||
" c_matrix = confusion_matrix(y_test_clf, y_pred)\n",
|
||
"\n",
|
||
" # Сохранение результатов\n",
|
||
" results_classification[name] = {\n",
|
||
" \"Best Params\": grid_search.best_params_,\n",
|
||
" \"Accuracy\": acc,\n",
|
||
" \"F1 Score\": f1,\n",
|
||
" \"Confusion_matrix\": c_matrix\n",
|
||
" }\n",
|
||
"\n",
|
||
"# Печать результатов\n",
|
||
"for name, metrics in results_classification.items():\n",
|
||
" print(f\"\\nModel: {name}\")\n",
|
||
" for metric, value in metrics.items():\n",
|
||
" print(f\"{metric}: {value}\")"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"Вывод: Все три модели показывают высокую точность, что указывает на их способность хорошо справляться с задачей классификации на данном наборе данных."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"Нарисуем матрицу ошибок"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 59,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"image/png": "iVBORw0KGgoAAAANSUhEUgAAA/EAAANrCAYAAAAOPBiwAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAADQN0lEQVR4nOzdd3xT9f7H8Xe60t1S6GCUIShDGYqKvWwFCuJAcCFqCwqC4IArIipb6RUHijKcVL304kJUVIYIiAJeQVBEqCwFhbJpmR3J+f3RX3MNpZDmpE3Tvp6Px3k87Mk5J598icnnk+84FsMwDAEAAAAAgArPz9sBAAAAAAAA11DEAwAAAADgIyjiAQAAAADwERTxAAAAAAD4CIp4AAAAAAB8BEU8AAAAAAA+giIeAAAAAAAfQREPAAAAAICPoIgHAAAAAMBHUMTDJ3Xq1EmdOnXy2PXq16+v1NRUj12vKlm+fLksFouWL1/u7VAAAFVAamqq6tev7+0wqpTff/9dFotF6enpXovhbLna1q1b1a1bN0VFRclisWj+/PlKT0+XxWLR77//7pU4gfJAEQ/Tij4s165d6+1QzmnVqlUaP368jh496pHrFX2hFW1+fn6KiYlRjx49tHr1ao88BwAA3lT0HV+0BQQEqHbt2kpNTdVff/3l7fDKXWpqqlN7/H1buHCht8MrZs+ePRo/frw2bNhQ4jHLly9X7969lZCQoKCgIMXFxen666/XvHnzyi9QN6WkpGjjxo16+umn9e677+ryyy/3dkhAuQjwdgCAOxYvXlzqc1atWqUJEyYoNTVV0dHRTo9lZmbKz8+937T69u2ra6+9VjabTb/99ptmzJihzp0764cfflDz5s3duqYv6dChg06dOqWgoCBvhwIAKCMTJ05UgwYNdPr0aa1Zs0bp6en69ttv9csvvyg4ONjb4ZUrq9WqN954o9j+li1beiGac9uzZ48mTJig+vXrq1WrVsUeHzdunCZOnKgLL7xQ9913n+rVq6dDhw7piy++UJ8+fTRnzhzdcccd5R/4WZyZq506dUqrV6/WE088oWHDhjn233XXXbr99ttltVq9ESZQLiji4ZM8XTCa+aC/7LLLdOeddzr+bt++vXr06KGZM2dqxowZngjPZSdOnFBYWFi5Pqefn1+VS+AAoKrp0aOHo5fz3nvvVY0aNfTMM8/o008/1a233url6MpXQECA0/e+J508eVKhoaFlcu0zffjhh5o4caJuvvlmZWRkKDAw0PHYyJEjtWjRIuXn55dLLK44M1c7cOCAJBXrmPH395e/v7/HntcbuRVwPgynR7lYv369evToocjISIWHh+uaa67RmjVrih33888/q2PHjgoJCVGdOnX01FNPafbs2cXmNp1tTvzLL7+siy++WKGhoapWrZouv/xyZWRkSJLGjx+vkSNHSpIaNGjgGPpWdM2zzbM6evSohg8frvr168tqtapOnTq6++67dfDgwXO+1vbt20uStm/fXux6Dz/8sBITE2W1WtWoUSM988wzstvtTscdOnRId911lyIjIxUdHa2UlBT99NNPxeaipaamKjw8XNu3b9e1116riIgI9evXT5Jkt9v14osv6uKLL1ZwcLDi4+N133336ciRI07PtXbtWiUnJ6tGjRoKCQlRgwYNNGDAAKdj5s6dq9atWysiIkKRkZFq3ry5XnrpJcfjJc2J/+CDD9S6dWuFhISoRo0auvPOO4sNvSx6DX/99Zd69eql8PBwxcbG6pFHHpHNZjtnOwMAvOfM77q8vDyNHTtWrVu3VlRUlMLCwtS+fXstW7bM6byiqWjPPfecXnvtNTVs2FBWq1VXXHGFfvjhh2LPM3/+fF1yySUKDg7WJZdcoo8//vis8Zw4cUL//Oc/Hd+xjRs31nPPPSfDMJyOs1gsGjZsmD744AM1a9ZMISEhSkpK0saNGyVJr776qho1aqTg4GB16tTJ7XnVM2bM0MUXXyyr1apatWpp6NChxabzderUSZdcconWrVunDh06KDQ0VI8//rgkKTc3V+PGjVOjRo1ktVqVmJioRx99VLm5uU7XWLJkidq1a6fo6GiFh4ercePGjmssX75cV1xxhSSpf//+jtynKJcYM2aMYmJi9NZbbzkV8EWSk5N13XXXlfgaf/75Z6WmpuqCCy5QcHCwEhISNGDAAB06dMjpuGPHjunhhx925FNxcXHq2rWrfvzxR8cxW7duVZ8+fZSQkKDg4GDVqVNHt99+u7Kzsx3H/D1XGz9+vOrVqyep8AcHi8XiWCehpDnxX375pdq3b6+wsDBFRESoZ8+e2rRpk9Mx58qtgIqEnniUuU2bNql9+/aKjIzUo48+qsDAQL366qvq1KmTVqxYoTZt2kiS/vrrL3Xu3FkWi0WjR49WWFiY3njjDZd6yV9//XU9+OCDuvnmm/XQQw/p9OnT+vnnn/X999/rjjvuUO/evfXbb7/pP//5j6ZOnaoaNWpIkmJjY896vePHj6t9+/bavHmzBgwYoMsuu0wHDx7Up59+qj///NNx/tkUfWlUq1bNse/kyZPq2LGj/vrrL913332qW7euVq1apdGjR2vv3r168cUXJRUW39dff73++9//asiQIWrSpIk++eQTpaSknPW5CgoKlJycrHbt2um5555z/Hp/3333KT09Xf3799eDDz6onTt36pVXXtH69ev13XffKTAwUPv371e3bt0UGxurxx57TNHR0fr999+d5sAtWbJEffv21TXXXKNnnnlGkrR582Z99913euihh0psg6LnvuKKK5SWlqZ9+/bppZde0nfffaf169c7/Wpus9mUnJysNm3a6LnnntNXX32l559/Xg0bNtSQIUNKfA4AgPec+V2Xk5OjN954Q3379tXAgQN17Ngxvfnmm0pOTtZ///vfYkO5MzIydOzYMd13332yWCyaMmWKevfurR07djgKysWLF6tPnz5q1qyZ0tLSdOjQIfXv31916tRxupZhGLrhhhu0bNky3XPPPWrVqpUWLVqkkSNH6q+//tLUqVOdjl+5cqU+/fRTDR06VJKUlpam6667To8++qhmzJih+++/X0eOHNGUKVM0YMAAff3118Ve/5k/6AcGBioqKkpSYYE5YcIEdenSRUOGDFFmZqZmzpypH374wfEdXOTQoUPq0aOHbr/9dt15552Kj4+X3W7XDTfcoG+//VaDBg1S06ZNtXHjRk2dOlW//fab5s+fL6kwv7ruuuvUokULTZw4UVarVdu2bdN3330nSWratKkmTpyosWPHatCgQY4fXv7xj39o69at2rJliwYMGKCIiAiX/s3PtGTJEu3YsUP9+/dXQkKCNm3apNdee02bNm3SmjVrZLFYJEmDBw/Whx9+qGHDhqlZs2Y6dOiQvv32W23evFmXXXaZ8vLylJycrNzcXD3wwANKSEjQX3/9pQULFujo0aOOdv273r17Kzo6WsOHD3dMawwPDy8x1nfffVcpKSlKTk7WM888o5MnT2rmzJlq166d1q9f77RQYkm5FVChGIBJs2fPNiQZP/zww1kf79WrlxEUFGRs377dsW/Pnj1GRESE0aFDB8e+Bx54wLBYLMb69esd+w4dOmTExMQYkoydO3c69nfs2NHo2LGj4+8bb7zRuPjii88Z57PPPlvsOkXq1atnpKSkOP4eO3asIcmYN29esWPtdrthGIaxc+dOQ5IxYcIE48CBA0ZWVpaxcuVK44orrjAkGR988IHjnEmTJhlhYWHGb7/95nStxx57zPD39zd27dplGIZhfPTRR4Yk48UXX3QcY7PZjKuvvtqQZMyePduxPyUlxZBkPPbYY07XXLlypSHJmDNnjtP+hQsXOu3/+OOPz/nvZhiG8dBDDxmRkZFGQUFBiccsW7bMkGQsW7bMMAzDyMvLM+Li4oxLLrnEOHXqlOO4BQsWGJKMsWPHFnsNEydOdLrmpZdearRu3brE5wQAlI+i7/ivvvrKOHDggLF7927jww8/NGJjYw2r1Wrs3r3bMAzDKCgoMHJzc53OPXLkiBEfH28MGDDAsa/ou7N69erG4cOHHfs/+eQTQ5Lx2WefOfa1atXKqFmzpnH06FHHvsWLFxuSjHr16jn2zZ8/35BkPPXUU07Pf/PNNxsWi8XYtm2bY58kw2q1OuUCr776qiHJSEhIMHJychz7R48eXSxvKPreOnMrykn2799vBAUFGd26dTNsNpvjvFdeecWQZLz11luOfR07djQkGbNmzXKK+9133zX8/PyMlStXOu2fNWuWIcn47rvvDMMwjKlTpxqSjAMHDhgl+eGHH4rlD4bxv/aeOnVqief+XdG/29+vc/LkyWLH/ec//zEkGd98841jX1RUlDF06NASr71+/fpiedPZnJmrFcX07LPPOh1X9J4t+nc7duyYER0dbQwcONDpuKysLCMqKsppf0m5FVDRMJweZcpms2nx4sXq1auXLrjgAsf+mjVr6o477tC3336rnJwcSdLChQuVlJTk9Gt9TEyMS8OYoqOj9eeff551KJ47PvroI7Vs2VI33XRTsceKflkuMm7cOMXGxiohIcHRe//888/r5ptvdhzzwQcfqH379qpWrZoOHjzo2Lp06SKbzaZvvvlGUmEbBAYGauDAgY5z/fz8HL0FZ3Nmb/UHH3ygqKgode3a1em5WrdurfDwcMfQxqLe8AULFpQ45y06OlonTpzQkiVLztFaztauXav9+/fr/vvvd5or37NnTzVp0kSff/55sXMGDx7s9Hf79u21Y8cOl58TAFC2unTpotjYWCUmJurmm29W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1au1aNGiYscfPXpUBQUFkgrbID8/X6+//rrjcbvdrunTp5835iK33nqrbDabJk2aVOyxgoICx+s/cuRIsddStB5B0ZD6M9vVz89PLVq0cDrmTJdffrni4uI0a9Ysp2O+/PJLbd68WT179nT5tQAAKqZOnTrpyiuv1IsvvqjTp087en3//r3y/fffa/Xq1W5dv2bNmmrVqpXefvttp2HVS5Ys0a+//up07LXXXiubzaZXXnnFaf/UqVNlsVicCsWy1qVLFwUFBWnatGlObfHmm28qOzvbpe/AW2+9VX/99ZdTLlDk1KlTOnHihKTCHOlMZ36Pnyv3mTBhgg4dOqR7773XkYf83eLFi7VgwYKzxni2f29JjrvtFLHZbMWGxcfFxalWrVqOGHNycoo9f/PmzeXn51dirlEaycnJioyM1OTJk8+6BlDR/eYBX0JPPDzmrbfeOut86fHjxzvuY3r//fcrICBAr776qnJzczVlyhTHcY8++qj+/e9/q2vXrnrggQcct5irW7euDh8+fM5fo7t166aEhAS1bdtW8fHx2rx5s1555RX17NnT8at80Xy1J554QrfffrsCAwN1/fXXO77g/m7kyJH68MMPdcstt2jAgAFq3bq1Dh8+rE8//VSzZs1Sy5Ytz9kWDz30kF588UX961//0ty5czVy5Eh9+umnuu6665SamqrWrVvrxIkT2rhxoz788EP9/vvvqlGjhnr16qUrr7xS//znP7Vt2zY1adJEn376qeOL2pXRBB07dtR9992ntLQ0bdiwQd26dVNgYKC2bt2qDz74QC+99JJuvvlmvf3225oxY4ZuuukmNWzYUMeOHdPrr7+uyMhIXXvttZKke++9V4cPH9bVV1+tOnXq6I8//tDLL7+sVq1aOeYanikwMFDPPPOM+vfvr44dO6pv376OW8zVr19fw4cPP+9rAABUfCNHjtQtt9yi9PR0XXfddZo3b55uuukm9ezZUzt37tSsWbPUrFkzHT9+3K3rp6WlqWfPnmrXrp0GDBigw4cP6+WXX9bFF1/sdM3rr79enTt31hNPPKHff/9dLVu21OLFi/XJJ5/o4YcfdvTElofY2FiNHj1aEyZMUPfu3XXDDTcoMzNTM2bM0BVXXKE777zzvNe466679P7772vw4MFatmyZ2rZtK5vNpi1btuj999/XokWLdPnll2vixIn65ptv1LNnT9WrV0/79+/XjBkzVKdOHbVr105SYS90dHS0Zs2apYiICIWFhalNmzZq0KCBbrvtNm3cuFFPP/201q9fr759+6pevXo6dOiQFi5cqKVLlyojI+OsMUZGRqpDhw6aMmWK8vPzVbt2bS1evFg7d+50Ou7YsWOqU6eObr75ZrVs2VLh4eH66quv9MMPPzgWA/z66681bNgw3XLLLbroootUUFCgd999V/7+/urTp4/Jf5HCWGfOnKm77rpLl112mW6//XbFxsZq165d+vzzz9W2bdtiPwABFZ7X1sVHpVF0K4+Stt27dxs//vijkZycbISHhxuhoaFG586djVWrVhW71vr164327dsbVqvVqFOnjpGWlmZMmzbNkGRkZWU5jjvzFnOvvvqq0aFDB6N69eqG1Wo1GjZsaIwcOdLIzs52uv6kSZOM2rVrG35+fk63HznztiWGUXh7u2HDhhm1a9c2goKCjDp16hgpKSnGwYMHDcMo+dYmRVJTUw1/f3/HrW2OHTtmjB492mjUqJERFBRk1KhRw/jHP/5hPPfcc0ZeXp7jvAMHDhh33HGHERERYURFRRmpqanGd999Z0gy5s6d6zguJSXFCAsLK/Hf5bXXXjNat25thISEGBEREUbz5s2NRx991NizZ49hGIbx448/Gn379jXq1q1rWK1WIy4uzrjuuuuMtWvXOq7x4YcfGt26dTPi4uKMoKAgo27dusZ9991n7N2713HMmbeYK/Lee+8Zl156qWG1Wo2YmBijX79+xp9//ul0TEmvYdy4cQYfTwDgfee6jazNZjMaNmxoNGzY0CgoKDAmT55s1KtXz7Barcall15qLFiwwEhJSXG6Hdy5vjslGePGjXPa99FHHxlNmzY1rFar0axZM2PevHnFrmkYhd+xw4cPN2rVqmUEBgYaF154ofHss886bgv79+c483ZnJcVU9P3291ufne+7t8grr7xiNGnSxAgMDDTi4+ONIUOGGEeOHHE6pmPHjiXeHjcvL8945plnjIsvvtiwWq1GtWrVjNatWxsTJkxw5DZLly41brzxRqNWrVpGUFCQUatWLaNv377Fbmf7ySefGM2aNTMCAgLOeru5ouvExcUZAQEBRmxsrHH99dcbn3zySbE2+vu5f/75p3HTTTcZ0dHRRlRUlHHLLbcYe/bscfp3zM3NNUaOHGm0bNnSiIiIMMLCwoyWLVsaM2bMcFxnx44dxoABA4yGDRsawcHBRkxMjNG5c2fjq6++corT3VvMFVm2bJmRnJxsREVFGcHBwUbDhg2N1NRUp7zH1X9fwNsshlEOK4gAJjz88MN69dVXdfz48Sq7CNr8+fN100036dtvv1Xbtm29HQ4AAAAAL2FOPCqUU6dOOf196NAhvfvuu2rXrl2VKeDPbAObzaaXX35ZkZGRuuyyy7wUFQAAAICKgDnxqFCSkpLUqVMnNW3aVPv27dObb76pnJwcjRkzxtuhlZsHHnhAp06dUlJSknJzczVv3jytWrVKkydPdmm1eaC8nT59Wnl5eaauERQUpODgYA9FBAAAKiqzeQM5g8RwelQojz/+uD788EP9+eefslgsuuyyyzRu3LgqdUuQjIwMPf/889q2bZtOnz6tRo0aaciQIRo2bJi3QwOKOX36tBrUC1fWfpup6yQkJGjnzp1V/ksZAIDKzBN5AzkDRTwAwIScnBxFRUVp57p6ioxwb4ZWzjG7GrT+Q9nZ2Y5bTgIAgMrHbN5AzlCI4fQAANPCwgs3d9j4KRkAgCrF3byBnKEQC9sBAAAAAOAjqkRPvN1u1549exQRESGLxeLtcADAawzD0LFjx1SrVi35+Xnud1y7DNnl3s/j7p4HlBXyBgAoVNHyBnKGQlWiiN+zZ48SExO9HQYAVBi7d+9WnTp1PHY9u+yymzgXqEjIGwDAWUXJG8gZClWJIj4iIkKS1L7VCAX4W70cje8y1v3q7RAAmFSgfH2rLxyfi55iMwzZ3Fwn1d3zgLJC3uAZ5A2A76toeQM5Q6EqUcQXDYUL8LcqwL/q3orALMMS6O0QAJj1/999nh4izHB6VCbkDZ5B3gBUAhUsbyBnKMTCdgAAAAAA+Igq0RMPAChbdhmy0RMPAABc4G7eQM5QiCIeAGAaw+kBAICrGE5vDkU8AMA0FrYDAACuYmE7c5gTDwAAAACAj6CIBwCYZje5lcbMmTPVokULRUZGKjIyUklJSfryyy8dj58+fVpDhw5V9erVFR4erj59+mjfvn1O19i1a5d69uyp0NBQxcXFaeTIkSooKHDnpQMAgFIiZzCHIh4AYJrt/xeocXcrjTp16uhf//qX1q1bp7Vr1+rqq6/WjTfeqE2bNkmShg8frs8++0wffPCBVqxYoT179qh3797/i9VmU8+ePZWXl6dVq1bp7bffVnp6usaOHevRNgEAAGdHzmCOxTAq/8SCnJwcRUVFqXPr0dzv1QTjh43eDgGASQVGvpbrE2VnZysyMtL09Yo+X3/+NU4REe79LnzsmF0tmu03FVNMTIyeffZZ3XzzzYqNjVVGRoZuvvlmSdKWLVvUtGlTrV69WldddZW+/PJLXXfdddqzZ4/i4+MlSbNmzdKoUaN04MABBQUFuRUDKg/yBs8gbwB8X0XLG8gZCtETDwCoEHJycpy23Nzc855js9k0d+5cnThxQklJSVq3bp3y8/PVpUsXxzFNmjRR3bp1tXr1aknS6tWr1bx5c8eXsSQlJycrJyfH8cs8AACouKp6zkARDwAwzRNz4hMTExUVFeXY0tLSSny+jRs3Kjw8XFarVYMHD9bHH3+sZs2aKSsrS0FBQYqOjnY6Pj4+XllZWZKkrKwspy/joseLHgMAAGWLnMEcbjEHADDNLotssrh9riTt3r3baWic1Wot8ZzGjRtrw4YNys7O1ocffqiUlBStWLHCrecHAADly928gZyhEEU8AMA0u1G4uXuuJMfKsa4ICgpSo0aNJEmtW7fWDz/8oJdeekm33Xab8vLydPToUadf1vft26eEhARJUkJCgv773/86Xa9oJdqiYwAAQNlxN28gZyjEcHoAgGm2//9F3d3NLLvdrtzcXLVu3VqBgYFaunSp47HMzEzt2rVLSUlJkqSkpCRt3LhR+/fvdxyzZMkSRUZGqlmzZqZjAQAA50bOYA498QAAnzJ69Gj16NFDdevW1bFjx5SRkaHly5dr0aJFioqK0j333KMRI0YoJiZGkZGReuCBB5SUlKSrrrpKktStWzc1a9ZMd911l6ZMmaKsrCw9+eSTGjp06DmH4wEAAN9SWXMGingAgGlmfh0v7Xn79+/X3Xffrb179yoqKkotWrTQokWL1LVrV0nS1KlT5efnpz59+ig3N1fJycmaMWOG43x/f38tWLBAQ4YMUVJSksLCwpSSkqKJEye6FT8AACgdd/MGcoZC3CceLuN+r4DvK6v7vX77Sy2Fu3mf+OPH7Gp3yR6PxQSYRd7gGeQNgO+raHkDOUMheuIBAKaVZ088AADwbeXVE19ZsbAdAAAAAAA+gp54AIBpNvnJ5ubvwjYPxwIAACo2d/MGcoZCFPEAANMMwyK74d4QN8PN8wAAgG9yN28gZyhEEQ8AMI058QAAwFXMiTeHOfEAAAAAAPgIeuIBAKbZDD/ZDDfnxFf6G50CAIC/czdvIGcoRBEPADDNLovsbg7usotvZAAAqhJ38wZyhkIU8QAA05gTDwAAXMWceHOYEw8AAAAAgI+gJx4AYJq5OfEMjQMAoCpxf048OYNEEQ8A8IDCuW3uDXFz9zwAAOCb3M0byBkKUcQDAEyzy082FrYDAAAucDdvIGcoRBEPADCN4fQAAMBVDKc3h4XtAAAAAADwEfTEAwBMs8uP+8QDAACXuJs3kDMUoogvR3fe/pPu7LvRad/uPyM1cOgNkqTAQJsGDVinju1+V2CgXevW19Qrs67U0ewQb4TrU65PPaibh+xXTGyBdvwaohlP1lbmhlBvh+VTaEPzqnIb2gyLbIab94l38zygsiNvKDtV+fPaU2hD86pyG7qbN5AzFPLqcPrU1FRZLJZiW/fu3SVJ9evXl8Vi0Zo1a5zOe/jhh9WpUycvRGze739EqW9KH8f2z8e6OR677561anPFn3p6SgeNfKKrqsec0pjR33gxWt/Q8YYjGjRuj+a8kKChyRdpx6/Bejpjh6Kq53s7NJ9BG5pX1dvQ9v8L1Li7Aa4gbyBv8ISq/nntCbSheVW9DckZzPF6K3Tv3l179+512v7zn/84Hg8ODtaoUaO8GKFn2Wx+OnI0xLHlHAuWJIWG5im5y3a99lZr/bQxQdu2V9fz05J0cdMDanLRAS9HXbH1HnRQCzNitPi9GO3aGqxpo+oo95RFyX0Pezs0n0EbmkcbAuWDvIG8wSw+r82jDc2jDWGG14t4q9WqhIQEp61atWqOxwcNGqQ1a9boiy++8GKUnlO7Vo7mzP5Is1+dr0dHfKvYGickSRc2PKzAQLvW/1TTceyff0Vp3/4wNW1y0FvhVngBgXZd2OKkflwZ4dhnGBatXxmhZq1PejEy30EbmkcbSnbDz9QGuIq8gbzBDD6vzaMNzaMNzeUNqABF/Pk0aNBAgwcP1ujRo2W32106Jzc3Vzk5OU5bRbDltxp6/qV/6MnxV+uVWVcqIf64nktbrJCQfFWrdkp5+X46cSLI6ZyjR4NVLfqUlyKu+CJjbPIPkI4ecF7e4cjBAFWLLfBSVL6FNjSPNmQ4PSoO8gbyhnPh89o82tA82pDh9GZ5vRUWLFig8PBwp23y5MlOxzz55JPauXOn5syZ49I109LSFBUV5dgSExPLIvRSW/tjba1cVU87/6imdetraczEqxUelqcObf/wdmgAYIpd/1ukprSba2UWUIi8gbwBgO9zN28gZyjk9SK+c+fO2rBhg9M2ePBgp2NiY2P1yCOPaOzYscrLyzvvNUePHq3s7GzHtnv37rIK35QTJ4L0154I1ap5TEeOhCgo0K6wMOfXFx19WkeOsspsSXIO+8tWIEWf8atltRoFOnKAmy+4gjY0jzYEyg95A3mDGXxem0cbmkcbwiyvF/FhYWFq1KiR0xYTE1PsuBEjRujUqVOaMWPGea9ptVoVGRnptFVEwcH5qplwXIePhGjr9hjl5/upVYssx+N1amcrPu6ENm+p4cUoK7aCfD9t/TlUl7Y75thnsRhq1e64fl1XNW7RYRZtaB5t+L/7vbq7Aa4ibyBvMIPPa/NoQ/NoQ3N5A3zoPvHh4eEaM2aMxo8frxtuuMHb4bjl3tR1+v6HOtp/IEwxMad0V9+fZLNbtPyb+jp5MkiLvmqoQQPW6djxIJ08Gaj7B/2gX7fU0JbfYr0deoU277UaeuTF3frtp1Blrg/VTQMPKDjUrsVziyd1ODva0Lyq3oY2w082Nxebcfc84FzIG1CSqv557Qm0oXlVvQ3dzRvIGQp5vYjPzc1VVlaW076AgADVqFH8V+RBgwZp6tSpysjIUJs2bcorRI+pUeOkHnvkW0VE5Co7O1ibNsdq+KPdlZ1TeLuYV9+8XIaxTmNGfaPAQJvWra+lV2Zd6eWoK74Vn1ZTVHWb7h6ZpWqxBdqxKURP9GugowcDvR2az6ANzavqbWiXRXZZ3D4XcBV5A3mDWVX989oTaEPzqnobups3kDMU8noRv3DhQtWsWdNpX+PGjbVly5ZixwYGBmrSpEm64447yis8j/rXc+3P+Xh+vr+mv3qlpr/KF3BpfTq7hj6dzfBBM2hD86pyG9ITj/JC3vA/5A3uq8qf155CG5pXlduQnnhzvFrEp6enKz09vcTHf//992L7+vbtq759+5ZdUAAAoEIibwAAoAL0xAMAfJ+Ze7dyz1cAAKoWd/MGcoZCFPEAANPshkV2w8058W6eBwAAfJO7eQM5QyGKeACAaXYTPfHcLgYAgKrF3byBnKEQrQAAAAAAgI+gJx4AYJrd8JPdzRVj3T0PAAD4JnfzBnKGQhTxAADTbLLI5ua9W909DwAA+CZ38wZyhkIU8QAA0+iJBwAArqIn3hxaAQAAAAAAH0FPPADANJvcH+Jm82woAACggnM3byBnKEQRDwAwjeH0AADAVQynN4ciHgBgms3wk83NL1Z3zwMAAL7J3byBnKEQRTwAwDRDFtndHE5vsNIsAABVirt5AzlDIX7KAAAAAADAR9ATDwAwjeH0AADAVQynN4dWAACYZjcspjZXpaWl6YorrlBERITi4uLUq1cvZWZmOh3TqVMnWSwWp23w4MFOx+zatUs9e/ZUaGio4uLiNHLkSBUUFHikLQAAwLmVR84gVd68gZ54AIBpNvnJ5ubvwqU5b8WKFRo6dKiuuOIKFRQU6PHHH1e3bt3066+/KiwszHHcwIEDNXHiRMffoaGh/3s+m009e/ZUQkKCVq1apb179+ruu+9WYGCgJk+e7NZrAAAArnM3byjtOZU1b6CIBwBUCDk5OU5/W61WWa1Wp30LFy50+js9PV1xcXFat26dOnTo4NgfGhqqhISEsz7P4sWL9euvv+qrr75SfHy8WrVqpUmTJmnUqFEaP368goKCPPSKAABAWXAlZ5Aqb97AcHoAgGmeGE6fmJioqKgox5aWlnbe583OzpYkxcTEOO2fM2eOatSooUsuuUSjR4/WyZMnHY+tXr1azZs3V3x8vGNfcnKycnJytGnTJk80BwAAOAdv5AxS5ckb6IkHAJhml5/sbv4uXHTe7t27FRkZ6dh/tl/Unc6z2/Xwww+rbdu2uuSSSxz777jjDtWrV0+1atXSzz//rFGjRikzM1Pz5s2TJGVlZTl9EUty/J2VleXWawAAAK5zN29wN2eQKlfeQBEPADDNZlhkK+ViM38/V5IiIyOdvpDPZ+jQofrll1/07bffOu0fNGiQ47+bN2+umjVr6pprrtH27dvVsGFDt2IEAACe427e4G7OIFWuvIHh9AAAnzNs2DAtWLBAy5YtU506dc55bJs2bSRJ27ZtkyQlJCRo3759TscU/V3SfDgAAOC7KlveQBEPADCtvG4xZxiGhg0bpo8//lhff/21GjRocN5zNmzYIEmqWbOmJCkpKUkbN27U/v37HccsWbJEkZGRatasWeleOAAAKLXyusVcZc0bGE4PADDNMPxkN9z7XdgoxXlDhw5VRkaGPvnkE0VERDjmokVFRSkkJETbt29XRkaGrr32WlWvXl0///yzhg8frg4dOqhFixaSpG7duqlZs2a66667NGXKFGVlZenJJ5/U0KFDXZpTBwAAzHE3byhNziBV3ryBIh4AYJpNFtnk5pz4Upw3c+ZMSVKnTp2c9s+ePVupqakKCgrSV199pRdffFEnTpxQYmKi+vTpoyeffNJxrL+/vxYsWKAhQ4YoKSlJYWFhSklJcbo/LAAAKDvu5g2lPaey5g0U8QAA0+yGSj3E7e/nusowzn1wYmKiVqxYcd7r1KtXT1988YXrTwwAADzG3byhNDmDVHnzBubEAwAAAADgI+iJBwCYZjcxJ97d8wAAgG9yN28gZyhEEQ8AMM0ui+xuzol39zwAAOCb3M0byBkKUcQDAEyzGRbZ3JwT7+55AADAN7mbN5AzFGI8AgAAAAAAPoKeeACAacyJBwAArmJOvDkU8QAA0+yyuH+LOea3AQBQpbibN5AzFKKIBwCYZphY2M7gCxkAgCrF3byBnKFQlSrijXW/yrAEejsMn/Xn6H94OwSfVydtlbdDAAC4iLzBHPIG88gbAJxNlSriAQBlw26YGE7PSrMAAFQp7uYN5AyFKOIBAKaxsB0AAHAVC9uZQxEPADCNnngAAOAqeuLNoYgHAJhmN7GwHSvNAgBQtbibN5AzFGI8AgAAAAAAPoKeeACAaQynBwAArmI4vTkU8QAA0yjiAQCAqyjizaGIBwCYRhEPAABcRRFvDnPiAQAAAADwEfTEAwBMoyceAAC4ip54cyjiAQCmGXL/ti+GZ0MBAAAVnLt5AzlDIYp4AIBp9MQDAABX0RNvDnPiAQAAAADwEfTEAwBMoyceAAC4ip54cyjiAQCmUcQDAABXUcSbQxEPADCNIh4AALiKIt4c5sQDAAAAAOAj6IkHAJhmGBYZbv467u55AADAN7mbN5AzFKKIBwCYZpfF7fvEu3seAADwTe7mDeQMhSjiAQCmMSceAAC4ijnx5lDEAwBMYzg9AABwFcPpzWFhOwAAAAAAfAQ98QAA0xhODwAAXMVwenMo4gEApjGcHgAAuIrh9OZQxAMATDNM9MTzhQwAQNXibt5AzlCIOfEAAAAAAPgIeuIBAKYZkgzD/XMBAEDV4W7eQM5QiCIeAGCaXRZZ5ObCdm6eBwAAfJO7eQM5QyGKeACAaSxsBwAAXMXCduYwJx4AAAAAAB9BTzwAwDS7YZGF+8QDAAAXuJs3kDMUoogHAJhmGCYWtmOVGgAAqhR38wZyhkIMpwcAmFY0t83dzVVpaWm64oorFBERobi4OPXq1UuZmZlOx5w+fVpDhw5V9erVFR4erj59+mjfvn1Ox+zatUs9e/ZUaGio4uLiNHLkSBUUFHikLQAAwLmVR84gVd68gSIeAGBaeRXxK1as0NChQ7VmzRotWbJE+fn56tatm06cOOE4Zvjw4frss8/0wQcfaMWKFdqzZ4969+7teNxms6lnz57Ky8vTqlWr9Pbbbys9PV1jx471aJsAAICzK68ivrLmDQynBwD4jIULFzr9nZ6erri4OK1bt04dOnRQdna23nzzTWVkZOjqq6+WJM2ePVtNmzbVmjVrdNVVV2nx4sX69ddf9dVXXyk+Pl6tWrXSpEmTNGrUKI0fP15BQUHeeGkAAMDDKmveQBFfAVyfelA3D9mvmNgC7fg1RDOerK3MDaHeDqtCaF1rjwZctkHNYg8oLvykHvi8u77e0UCSFOBn04NX/Vft6+1SnagcHc8N0uo/62jqqqt04ESY4xpNYw9oxD/W6JL4/bLbLVqy/QJN+batTuYHeutlVUi8D82rym3oiYXtcnJynPZbrVZZrdZznpudnS1JiomJkSStW7dO+fn56tKli+OYJk2aqG7dulq9erWuuuoqrV69Ws2bN1d8fLzjmOTkZA0ZMkSbNm3SpZde6tbrAMpLVf6sOR/yhvLD+9C8qtyGZhe2cydnkCpP3lBhhtOnpqbKYrFo8ODBxR4bOnSoLBaLUlNTHcf26tWrfAMsIx1vOKJB4/ZozgsJGpp8kXb8GqynM3Yoqnq+t0OrEEIC85V5sLqeWtG+2GPBAQVqGntQs35orVvm3qyHvkhWg+ijeqXnl45jYsNO6M1en2lXdqT6vt9b9316nRrFHNHTXb4uz5dR4fE+NK+qt2HRAjXubpKUmJioqKgox5aWlnbO57Tb7Xr44YfVtm1bXXLJJZKkrKwsBQUFKTo62unY+Ph4ZWVlOY75+xdx0eNFj8E3kDdUzc+a8yFvKB+8D82r6m1Y3jmDVLnyhgpTxEuF/xhz587VqVOnHPtOnz6tjIwM1a1b14uRlZ3egw5qYUaMFr8Xo11bgzVtVB3lnrIoue9hb4dWIXz7Rz1NW9NGS3dcUOyx43lWDfzkei3a1ki/H62mn/cl6OkV7XVJ/AHVDD8mSepU/w/l2/301PIO+v1oNf2yP04TlndQt0Y7VDcqu7xfToXF+9C8qt6GhV+s7s5vK7zG7t27lZ2d7dhGjx59zuccOnSofvnlF82dO7ccXiEqIvKGqvdZcz7kDeWD96F5Vb0N3c8bCs8vbc4gVa68oUIV8ZdddpkSExM1b948x7558+apbt26lXJ4Y0CgXRe2OKkfV0Y49hmGRetXRqhZ65NejMx3hVvzZDeknNzC4TSB/jbl2/xk6H/DdXILCmeRXFZzr1dirGh4H5pHG3pGZGSk03auYXHDhg3TggULtGzZMtWpU8exPyEhQXl5eTp69KjT8fv27VNCQoLjmDNXnS36u+gY+AbyBj5rzCJvKD3eh+bRhuaVJmeQKl/eUKGKeEkaMGCAZs+e7fj7rbfeUv/+/Ut1jdzcXOXk5DhtFVFkjE3+AdLRA85LExw5GKBqsdzqqLSC/As04h+r9cVvF+pEfuECE9//WVs1Qk+p/6XrFehnU6Q1V8P/sUaSVCOMD0mJ96En0Ibltzq9YRgaNmyYPv74Y3399ddq0KCB0+OtW7dWYGCgli5d6tiXmZmpXbt2KSkpSZKUlJSkjRs3av/+/Y5jlixZosjISDVr1sxkS6C8kTdUrc8aTyJvcA/vQ/Now/Jbnb6y5g0Vroi/88479e233+qPP/7QH3/8oe+++0533nlnqa6RlpbmNEciMTGxjKJFRRHgZ9ML3RfLImnisg6O/dsPx+iJrzor9dKftHbI61pxT7r+zInQwRMhpf4QAFAyw+TmqqFDh+rf//63MjIyFBERoaysLGVlZTmGU0dFRemee+7RiBEjtGzZMq1bt079+/dXUlKSrrrqKklSt27d1KxZM91111366aeftGjRIj355JMaOnSoS4vioGIhb4A7yBsA7yqPnEGqvHlDhVudPjY2Vj179lR6eroMw1DPnj1Vo0aNUl1j9OjRGjFihOPvnJycCvmFnHPYX7YCKfqMX9yq1SjQkQMV7p+mwgrws+n57ktUK/K4+n98g+PX9CKf/3aRPv/tIlUPOalTBYEyDCml1c/anRPppYgrFt6H5tGGcuvX8b+f66qZM2dKkjp16uS0f/bs2Y5FzKZOnSo/Pz/16dNHubm5Sk5O1owZMxzH+vv7a8GCBRoyZIiSkpIUFhamlJQUTZw40a344V3kDVXrs8YTyBvM4X1oHm3oft5Q2nMqa95QId8lAwYM0LBhwyRJ06dPL/X5rt5iwNsK8v209edQXdrumFYvjJIkWSyGWrU7rk/Tq3s5Ot9Q9EVcL/qo+s+7Udmng0s89tCpwlt23NR0s3Jt/lq9q06Jx1YlvA/Now3Lj2Gc/zf44OBgTZ8+/ZzfH/Xq1dMXX3zhydDgReQNfNa4irzBPN6H5tGG5aey5g0Vsojv3r278vLyZLFYlJyc7O1wytS812rokRd367efQpW5PlQ3DTyg4FC7Fs+N8XZoFUJoYL7TarB1InPUpMZBZZ+26sDJUE3tsVhNYw9o6IJr5e9nqEZo4Xy17NNW5dv9JUl3tNio9XsTdDI/UP9I/FP/bLtaU1e10bG8ip+wlRfeh+ZV+TZ0Z4zb388FTCBvqEKfNedB3lA+eB+aV+Xb0N28gZxBUgUt4v39/bV582bHf1dmKz6tpqjqNt09MkvVYgu0Y1OInujXQEcPBno7tArh4rj9Su/9qePvUe1XSZLmb26s6d9frqsv+F2SNK/vB07npc67QT/8VVuSdEn8fg298geFBuVr55FqmrCsgz7LbFw+L8BH8D40r8q3oYnh9GKeKUwib6hCnzXnQd5QPngfmlfl29DdvIGcQVIFLeKlwtsGVBWfzq6hT2eXbv5eVfHDX7V18ctDSnz8XI8VeXzJNZ4MqdLifWheVW7Dwvu9un8uYBZ5AyTyhvLE+9C8qtyG7uYN5AyFKkwRn56efs7H58+f7/KxAIDyVV4L2wFFyBsAwHeV18J2lVWFu8UcAAAAAAA4uwrTEw8A8GGGxf15avyqDgBA1eJu3kDOIMnFIv7TTz89/0H/74YbbnA7GACAb2JOPP6OvAEAcC7MiTfHpSK+V69eLl3MYrHIZrOZiQcA4Iu4xRz+hrwBAHBO3GLOFJeKeLvdXtZxAACASoK8AQCAsmNqTvzp06cVHBzsqVgAAD6K1enhCvIGAIDE6vRmlXp1epvNpkmTJql27doKDw/Xjh07JEljxozRm2++6fEAAQA+wnBzQ6VG3gAAOCtyBreVuoh/+umnlZ6erilTpigoKMix/5JLLtEbb7zh0eAAAL6h6Bd1dzdUXuQNAIAzkTOYU+oi/p133tFrr72mfv36yd/f37G/ZcuW2rJli0eDAwAAvo28AQAAzyr1nPi//vpLjRo1KrbfbrcrPz/fI0EBAHwMq9OjBOQNAIBiWJ3elFL3xDdr1kwrV64stv/DDz/UpZde6pGgAAC+xmJyQ2VF3gAAKI6cwYxS98SPHTtWKSkp+uuvv2S32zVv3jxlZmbqnXfe0YIFC8oiRgBARUdPPEpA3gAAKIaeeFNK3RN/44036rPPPtNXX32lsLAwjR07Vps3b9Znn32mrl27lkWMAICKzt2V6VltttIjbwAAFEPOYIpb94lv3769lixZ4ulYAABAJUTeAACA57hVxEvS2rVrtXnzZkmF891at27tsaAAAD7GsBRu7p6LSo+8AQDg4G7eQM4gyY0i/s8//1Tfvn313XffKTo6WpJ09OhR/eMf/9DcuXNVp04dT8cIAKjgDKNwc/dcVF7kDQCAM7mbN5AzFCr1nPh7771X+fn52rx5sw4fPqzDhw9r8+bNstvtuvfee8siRgBARceceJSAvAEAUAw5gyml7olfsWKFVq1apcaNGzv2NW7cWC+//LLat2/v0eAAAIBvI28AAMCzSl3EJyYmKj8/v9h+m82mWrVqeSQoAICPYU48SkDeAAAohjnxppR6OP2zzz6rBx54QGvXrnXsW7t2rR566CE999xzHg0OAOAbLIa5DZUXeQMA4EzkDOa41BNfrVo1WSz/+9XjxIkTatOmjQICCk8vKChQQECABgwYoF69epVJoACACszMPDW+kCsd8gYAwDm5mzeQM0hysYh/8cUXyzgMAABQWZA3AABQdlwq4lNSUso6DgCAL2NOPP6GvAEAcE7MiTel1Avb/d3p06eVl5fntC8yMtJUQAAAH8RweriAvAEAIInh9CaVemG7EydOaNiwYYqLi1NYWJiqVavmtAEAqiDuE48SkDcAAIohZzCl1EX8o48+qq+//lozZ86U1WrVG2+8oQkTJqhWrVp65513yiJGAADgo8gbAADwrFIPp//ss8/0zjvvqFOnTurfv7/at2+vRo0aqV69epozZ4769etXFnECACoyhtOjBOQNAIBiGE5vSql74g8fPqwLLrhAUuE8tsOHD0uS2rVrp2+++caz0QEAfEPRAjXubqi0yBsAAMWQM5hS6iL+ggsu0M6dOyVJTZo00fvvvy+p8Jf26OhojwYHAPANFsPchsqLvAEAcCZyBnNKXcT3799fP/30kyTpscce0/Tp0xUcHKzhw4dr5MiRHg8QAOADWNgOJSBvAAAUQ85gSqnnxA8f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n//8R9OmTdPmzZv16quvKjw8XImJifroo48kSZmZmdq7d69eeuklSVJaWpreeecdzZo1S5s2bdLw4cN15513asWKFZIKk4bevXvr+uuv14YNG3TvvffqscceK3WbREREKD09Xb/++qteeuklvf7665o6darTMdu2bdP777+vzz77TAsXLtT69et1//33Ox6fM2eOxo4dq6efflqbN2/W5MmTNWbMGL399tuljgcAgIqCvKE48gbAhxlABZeSkmLceOONhmEYht1uN5YsWWJYrVbjkUcecTweHx9v5ObmOs559913jcaNGxt2u92xLzc31wgJCTEWLVpkGIZh1KxZ05gyZYrj8fz8fKNOnTqO5zIMw+jYsaPx0EMPGYZhGJmZmYYkY8mSJWeNc9myZYYk48iRI459p0+fNkJDQ41Vq1Y5HXvPPfcYffv2NQzDMEaPHm00a9bM6fFRo0YVu9aZJBkff/xxiY8/++yzRuvWrR1/jxs3zvD39zf+/PNPx74vv/zS8PPzM/bu3WsYhmE0bNjQyMjIcLrOpEmTjKSkJMMwDGPnzp2GJGP9+vUlPi8AAN5E3nB25A1A5cGcePiEBQsWKDw8XPn5+bLb7brjjjs0fvx4x+PNmzd3ms/2008/adu2bYqIiHC6zunTp7V9+3ZlZ2dr7969atOmjeOxgIAAXX755cWGxhXZsGGD/P391bFjR5fj3rZtm06ePKmuXbs67c/Ly9Oll14qSdq8ebNTHJKUlJTk8nMUee+99zRt2jRt375dx48fV0FBgSIjI52OqVu3rmrXru30PHa7XZmZmYqIiND27dt1zz33aODAgY5jCgoKFBUVVep4AADwFvKG8yNvAHwXRTx8QufOnTVz5kwFBQWpVq1aCghwfuuGhYU5/X38+HG1bt1ac+bMKXat2NhYt2IICQkp9TnHjx+XJH3++edOX4JS4Xw9T1m9erX69eunCRMmKDk5WVFRUZo7d66ef/75Usf6+uuvF0sO/P39PRYrAABljbzh3MgbAN9GEQ+fEBYWpkaNGrl8/GWXXab33ntPcXFxxX5VLlKzZk19//336tChg6TCX47XrVunyy677KzHN2/eXHa7XStWrFCXLl2KPV70i77NZnPsa9asmaxWq3bt2lXiL/FNmzZ1LLZTZM2aNed/kX+zatUq1atXT0888YRj3x9//FHsuF27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VaKIBwCULebEAwAAlA+KeACAaXYZslHEAwAAlDnPLU0MAAAAAADKFD3xAADTGE4PAABQPijiAQCmsbAdAABA+WA4PQDANLvJrTRmzpypFi1aKDIyUpGRkUpKStKXX37pePz06dMaOnSoqlevrvDwcPXp00f79u1zusauXbvUs2dPhYaGKi4uTiNHjlRBQYE7Lx0AAKBcUcQDAHxKnTp19K9//Uvr1q3T2rVrdfXVV+vGG2/Upk2bJEnDhw/XZ599pg8++EArVqzQnj171Lt3b8f5NptNPXv2VF5enlatWqW3335b6enpGjt2rLdeEgAAgMsYTg8AMM1mYnX60p53/fXXO/399NNPa+bMmVqzZo3q1KmjN998UxkZGbr66qslSbNnz1bTpk21Zs0aXXXVVVq8eLF+/fVXffXVV4qPj1erVq00adIkjRo1SuPHj1dQUJBbrwMAAKA80BMPADDNZpjbJCknJ8dpy83NPf/z2myaO3euTpw4oaSkJK1bt075+fnq0qWL45gmTZqobt26Wr16tSRp9erVat68ueLj4x3HJCcnKycnx9GbDwAAUFFRxAMATPPEnPjExERFRUU5trS0tBKfb+PGjQoPD5fVatXgwYP18ccfq1mzZsrKylJQUJCio6Odjo+Pj1dWVpYkKSsry6mAL3q86DEAAICKjOH0AIAKYffu3YqMjHT8bbVaSzy2cePG2rBhg7Kzs/Xhhx8qJSVFK1asKI8wAQAAvIoiHgBgml0W2WRx+1xJjtXmXREUFKRGjRpJklq3bq0ffvhBL730km677Tbl5eXp6NGjTr3x+/btU0JCgiQpISFB//3vf52uV7R6fdExAAAAFRXD6QEAptkNc5vp57fblZubq9atWyswMFBLly51PJaZmaldu3YpKSlJkpSUlKSNGzdq//79jmOWLFmiyMhINWvWzHwwAAAAZYieeACAaTYTPfGlPW/06NHq0aOH6tatq2PHjikjI0PLly/XokWLFBUVpXvuuUcjRoxQTEyMIiMj9cADDygpKUlXXXWVJKlbt25q1qyZ7rrrLk2ZMkVZWVl68sknNXTo0HMO4QcAAKgIKOIBAKaVZxG/f/9+3X333dq7d6+ioqLUokULLVq0SF27dpUkTZ06VX5+furTp49yc3OVnJysGTNmOM739/fXggULNGTIECUlJSksLEwpKSmaOHGi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MwyppLhq3/otO55XHbNFh3J/GSFTWiLlH/RXdOOSmgrR6/Acin3iAQAAXMRjuogCAgJ011136a677tK0adM0evRozZgxQ8OHD5d0aZuZFi1auDfIGrDqlUhNXHBQP3wZqJydl7alCgi06OOsCHeH5jVow8otndtQ/3NHoRo0KtGFsz7a8G64vtoapGczcyVJp4756edjdXRk36W57/u+D1BgPYsaNCpWSHiZ6gVb1HfoSf3txRg1iC1RVONivb3k0uJt3X9T4K7b8ki1/Tk0/d/haF0AAABUjcck8b/Wrl07rV692t1h1LhN74UrtH6Zhk3KU3iDUu39tq6eGtxUBScYqlxVtGHlCk746fk/xuvUMT8FBpepaduLejYzV116nJUkffBGpP7+0i8LRk78bUtJl+a9937g0tZoY6Ydlq+voXl/bKLiiz5qfcN5/e9buQoOY1G7/1brn0PmxAMAALiE25P4kydP6ve//71Gjhypjh07Kjg4WNu3b9e8efN03333WcudOXNGeXl5NnUDAwM9dqi8Pd5bFqn3lkW6OwyvRhtWLPWlK68HMXRinoZOzLtiGb860tgZRzR2xpHqDO2axHMIAACAmub2JD4oKEgJCQmaP3++cnNzVVJSori4OI0ZM0ZPPvmktdz06dM1ffp0m7oPP/yw0tPTXR0yAOBX2GIOAADANdyexJvNZqWlpSktLa3SMvv373ddQAAA+zGcHgAAwCXcnsQDAK4RJOMAAAA1jiQeAOA0htMDAAC4hkfsEw8AAAAAAK6OnngAgPOYEw8AAOASJPEAAKcxnB4AAMA1SOIBAM6jJx4AAMAlmBMPAAAAAICXoCceAOA0htMDAAC4Bkk8AMB5DKcHAABwCYbTAwCcZzh52OGzzz5Tv379FBsbK5PJpNWrV9uGYhiaPn26GjZsqLp166pXr1768ccfbcqcOnVKgwcPVkhIiMLCwjRq1CidPXvW3rsGAABwOZJ4AIBXOXfunDp16qTFixdXeH3evHlauHCh0tPT9cUXX6hevXpKSkrSxYsXrWUGDx6sb7/9VuvWrdOaNWv02WefaezYsa66BQAAAIcxnB4A4DRXzom/++67dffdd1d4zTAMLViwQE8//bTuu+8+SdIbb7yh6OhorV69Wg8++KB2796ttWvX6t///re6du0qSVq0aJHuuecevfDCC4qNjXXs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9fCIJN5sNlc6V3HIkCFatWqVhg8frs2bN2vq1KkqKSnR888/X+n7FRUV2WxNVFhYWO0xwzOERJTJ108qOG77KP98wk9xLSrfngoVM5kMPTLrsL75Vz39lHPtzt+uSeGRxZKkn0/UsTn/84k61mvXJIskkxN17ZCVlXXF6wEBAVq8eLEWL17sYEAAAACeyyOS+KtJT09X+/btNXjwYL311lv69NNPFRQUVGn5tLQ0zZo1y4URAteGlLmHFN/6gv7025buDgVepjoWtgMAAMDVuX1OvCStWbNGQUFBNsfcuXOt16OiojRnzhxlZWVp7Nixuu222674flOnTtXp06etx8GDB2v6FuAmhad8VVYqhTUotTkfHlmqn497xd+oPMa4Zw4poVehnvh9C5046u/ucLzWzycutV14pO3CiuGRJdZr1yQXzokHAACozTwiy+nZs6eWLFlicy4iIsL677KyMmVkZCgwMFDbtm1TaWmp/PwqD91sNle6vzCuLaUlPvrxq0DdcOsZ69Z8JpOhzree1XsZFS06hvIMjXvmsG7uc1qTft9C+Qf53nFG3kGzTh2ro86JBdq7u54kKTCoVK07ndEHmWxxBgAAAOd4RBJfr149tWjRotLrL7zwgvbu3avt27erR48emjt3rqZPn+7CCGtOQGCZYpv+Mk82Jq5Yza6/oDMFvjp++BrutatGq16J1MQFB/XDl4HK2Rmo3445roBAiz7Oirh6ZShl7iH17P+zZo5spgtnfRTe4FIP8rkzviq+6BGDdTxOQGCZYuMvWl9HNy5Ss7bndKbAT8ePmrV6eUM9+NghHd5fV/mHzBr6+EGdPOavreuu4WfSmR51euIBAACqzCOS+Cv59ttvNWPGDGVmZqpt27ZasmSJBg0apP79+6tjx47uDs9prTpd0PPv5FpfPzLriCTp45XhenFCE3eF5VU2vReu0PplGjYpT+ENSrX327p6anBTFfxqYTFUrF/ySUnSC+/ssTn/woQ4rXuT0QwVadn+rOat+Nb6+uGn9kuS1q1qoJcmt9RbrzRSQF2L/vhMroJCSvXt9hBNG9lOJcXX8B9FSOIBAABcwmQY7v3tafjw4crPzy+3xZyfn5/CwsJ00003qVWrVsrMzLReGzRokHJycvSvf/3risPqLyssLFRoaKhu133yM5HYwY1Mji7fjct8AgPdHYJXKzWK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Sbp48aIyMzPVpEkTN0fn+QYOHKji4mItX75czZo1U35+vtavX6+TJ09ay8yePVtjxoyxqRccHOzqUD1WZd/L4eHhWrRokR5++GHdfffdatmypS5cuKDk5GSNHj1avXv3dlPEAAAAuBaQxLuY2Wy+4gq5Y8eOVXp6uj788EPdc889LozMu9x4443Kzc3VqlWrNHjwYEnSqlWr1KRJEzVt2tTN0Xm2goICbd68WRs3blSPHj0kSfHx8erWrZtNueDgYFb7voIrfS8PGTJEq1at0vDhw7V582ZNnTpVJSUlev75510cJQAAAK41rE7vYZo2bapHHnlEU6dOlcVicXc4Hm3kyJE2PaFLly5lYasqCAoKUlBQkFavXq2ioiJ3h3PNSk9P148//qjBgwfrL3/5i5YtW6agoCB3hwUAAAAvRxLvYmvWrLEmUZePuXPn2pR5+umntW/fPq1YscJNUXqHIUOGaMuWLfrpp5/0008/6fPPP9eQIUPcHZbH8/PzU0ZGhpYvX66wsDDdcsstevLJJ/XVV1/ZlJs8eXK5Z3Xz5s1uitrzXO17OSoqSnPmzFFWVpbGjh2r2267zY3RAgAA4FpBEu9iPXv21K5du2yORx55xKZMgwYNNHHiRE2fPl3FxcVuitTzNWjQQH379lVGRoaWLVumvn37KjIy0t1heYWBAwfqyJEjeu+999SnTx9t3LhRN954ozIyMqxlJk2aVO5Z7dq1q/uC9jBX+14uKytTRkaGAgMDtW3bNpWWlroxWgC/tnjxYl133XUKCAhQQkKC/vWvf12x/FtvvaU2bdooICBAHTp00IcffuiiSD2XPW346quvqnv37goPD1d4eLh69ep11TavDex9Di/LysqSyWRS//79azZAL2BvGxYUFGjcuHFq2LChzGazWrVqVau/n+1tvwULFqh169aqW7eu4uLiNGHCBF28eNFF0Xqezz77TP369VNsbKxMJpNWr1591TqXf+82m81q0aKFze/fVUUS72L16tVTixYtbI6IiIhy5VJTU3XhwgW9/PLLbojSe4wcOdLaqzxy5Eh3h+NVAgICdNddd2natGnaunWrhg8frhkzZlivR0ZGlntWLy8iiKt/L7/wwgvau3evtm/frkOHDpUbcQPAfVauXKnU1FTNmDFD//nPf9SpUyclJSXp2LFjFZbfunWrBg0apFGjRmnn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",
|
||
"text/plain": [
|
||
"<Figure size 1200x1000 with 7 Axes>"
|
||
]
|
||
},
|
||
"metadata": {},
|
||
"output_type": "display_data"
|
||
}
|
||
],
|
||
"source": [
|
||
"from sklearn.metrics import ConfusionMatrixDisplay\n",
|
||
"\n",
|
||
"# Визуализация матриц ошибок\n",
|
||
"num_models = len(results_classification)\n",
|
||
"num_rows = (num_models // 2) + (num_models % 2) # Количество строк для подграфиков\n",
|
||
"fig, ax = plt.subplots(num_rows, 2, figsize=(12, 10), sharex=False, sharey=False)\n",
|
||
"\n",
|
||
"for index, (name, metrics) in enumerate(results_classification.items()):\n",
|
||
" c_matrix = metrics[\"Confusion_matrix\"]\n",
|
||
" disp = ConfusionMatrixDisplay(\n",
|
||
" confusion_matrix=c_matrix, display_labels=['EN', 'MI', 'SE', 'EX']\n",
|
||
" ).plot(ax=ax.flat[index])\n",
|
||
" disp.ax_.set_title(name)\n",
|
||
"\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": [
|
||
"Формируем таблицу метрик классификации"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 60,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/html": [
|
||
"<style type=\"text/css\">\n",
|
||
"#T_3cbcd_row0_col0, #T_3cbcd_row1_col0 {\n",
|
||
" background-color: #21918c;\n",
|
||
" color: #f1f1f1;\n",
|
||
" background-color: #da5a6a;\n",
|
||
" color: #f1f1f1;\n",
|
||
"}\n",
|
||
"#T_3cbcd_row0_col1, #T_3cbcd_row1_col1 {\n",
|
||
" background-color: #21918c;\n",
|
||
" color: #f1f1f1;\n",
|
||
"}\n",
|
||
"#T_3cbcd_row2_col0 {\n",
|
||
" background-color: #440154;\n",
|
||
" color: #f1f1f1;\n",
|
||
" background-color: #4e02a2;\n",
|
||
" color: #f1f1f1;\n",
|
||
"}\n",
|
||
"#T_3cbcd_row2_col1 {\n",
|
||
" background-color: #440154;\n",
|
||
" color: #f1f1f1;\n",
|
||
"}\n",
|
||
"</style>\n",
|
||
"<table id=\"T_3cbcd\">\n",
|
||
" <thead>\n",
|
||
" <tr>\n",
|
||
" <th class=\"blank level0\" > </th>\n",
|
||
" <th id=\"T_3cbcd_level0_col0\" class=\"col_heading level0 col0\" >Accuracy</th>\n",
|
||
" <th id=\"T_3cbcd_level0_col1\" class=\"col_heading level0 col1\" >F1 Score</th>\n",
|
||
" </tr>\n",
|
||
" </thead>\n",
|
||
" <tbody>\n",
|
||
" <tr>\n",
|
||
" <th id=\"T_3cbcd_level0_row0\" class=\"row_heading level0 row0\" >LogisticRegression</th>\n",
|
||
" <td id=\"T_3cbcd_row0_col0\" class=\"data row0 col0\" >1.000000</td>\n",
|
||
" <td id=\"T_3cbcd_row0_col1\" class=\"data row0 col1\" >1.000000</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th id=\"T_3cbcd_level0_row1\" class=\"row_heading level0 row1\" >RandomForestClassifier</th>\n",
|
||
" <td id=\"T_3cbcd_row1_col0\" class=\"data row1 col0\" >1.000000</td>\n",
|
||
" <td id=\"T_3cbcd_row1_col1\" class=\"data row1 col1\" >1.000000</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th id=\"T_3cbcd_level0_row2\" class=\"row_heading level0 row2\" >KNN</th>\n",
|
||
" <td id=\"T_3cbcd_row2_col0\" class=\"data row2 col0\" >0.994094</td>\n",
|
||
" <td id=\"T_3cbcd_row2_col1\" class=\"data row2 col1\" >0.964127</td>\n",
|
||
" </tr>\n",
|
||
" </tbody>\n",
|
||
"</table>\n"
|
||
],
|
||
"text/plain": [
|
||
"<pandas.io.formats.style.Styler at 0x27c0bf32b40>"
|
||
]
|
||
},
|
||
"execution_count": 60,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"# Формируем таблицу метрик классификации\n",
|
||
"clf_metrics = pd.DataFrame.from_dict(results_classification, orient=\"index\")[[\"Accuracy\", \"F1 Score\"]]\n",
|
||
"\n",
|
||
"# Визуализация результатов с помощью стилизации\n",
|
||
"styled_metrics_clf = (\n",
|
||
" clf_metrics.sort_values(by=\"F1 Score\", ascending=False) # Сортировка по F1 Score\n",
|
||
" .style.background_gradient(cmap=\"viridis\", low=0, high=1, subset=[\"F1 Score\", \"Accuracy\"]) # Стилизация столбцов\n",
|
||
" .background_gradient(cmap=\"plasma\", low=0.3, high=1, subset=[\"Accuracy\"])\n",
|
||
")\n",
|
||
"\n",
|
||
"styled_metrics_clf"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"В итоге RandomForestClassifier и LogisticRegression выдали точность в 100% что я считаю это очень хорошо, но я не уверен что это правда. KNN очень близко."
|
||
]
|
||
}
|
||
],
|
||
"metadata": {
|
||
"kernelspec": {
|
||
"display_name": "aimenv",
|
||
"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.5"
|
||
}
|
||
},
|
||
"nbformat": 4,
|
||
"nbformat_minor": 2
|
||
}
|