1072 lines
106 KiB
Plaintext
Raw Permalink Normal View History

2024-12-06 22:30:14 +04:00
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Начало лабораторной работы"
]
},
{
"cell_type": "code",
"execution_count": 3,
2024-12-06 22:30:14 +04:00
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Index(['Unnamed: 0', 'Name', 'Brand', 'Model', 'Battery capacity (mAh)',\n",
" 'Screen size (inches)', 'Touchscreen', 'Resolution x', 'Resolution y',\n",
" 'Processor', 'RAM (MB)', 'Internal storage (GB)', 'Rear camera',\n",
" 'Front camera', 'Operating system', 'Wi-Fi', 'Bluetooth', 'GPS',\n",
" 'Number of SIMs', '3G', '4G/ LTE', 'Price'],\n",
" dtype='object')\n"
]
2024-12-12 15:54:39 +04:00
},
{
"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>Unnamed: 0</th>\n",
" <th>Name</th>\n",
" <th>Brand</th>\n",
" <th>Model</th>\n",
" <th>Battery capacity (mAh)</th>\n",
" <th>Screen size (inches)</th>\n",
" <th>Touchscreen</th>\n",
" <th>Resolution x</th>\n",
" <th>Resolution y</th>\n",
" <th>Processor</th>\n",
" <th>...</th>\n",
" <th>Rear camera</th>\n",
" <th>Front camera</th>\n",
" <th>Operating system</th>\n",
" <th>Wi-Fi</th>\n",
" <th>Bluetooth</th>\n",
" <th>GPS</th>\n",
" <th>Number of SIMs</th>\n",
" <th>3G</th>\n",
" <th>4G/ LTE</th>\n",
" <th>Price</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>0</td>\n",
" <td>OnePlus 7T Pro McLaren Edition</td>\n",
" <td>OnePlus</td>\n",
" <td>7T Pro McLaren Edition</td>\n",
" <td>4085</td>\n",
" <td>6.67</td>\n",
" <td>Yes</td>\n",
" <td>1440</td>\n",
" <td>3120</td>\n",
" <td>8</td>\n",
" <td>...</td>\n",
" <td>48.0</td>\n",
" <td>16.0</td>\n",
" <td>Android</td>\n",
" <td>Yes</td>\n",
" <td>Yes</td>\n",
" <td>Yes</td>\n",
" <td>2</td>\n",
" <td>Yes</td>\n",
" <td>Yes</td>\n",
" <td>58998</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>1</td>\n",
" <td>Realme X2 Pro</td>\n",
" <td>Realme</td>\n",
" <td>X2 Pro</td>\n",
" <td>4000</td>\n",
" <td>6.50</td>\n",
" <td>Yes</td>\n",
" <td>1080</td>\n",
" <td>2400</td>\n",
" <td>8</td>\n",
" <td>...</td>\n",
" <td>64.0</td>\n",
" <td>16.0</td>\n",
" <td>Android</td>\n",
" <td>Yes</td>\n",
" <td>Yes</td>\n",
" <td>Yes</td>\n",
" <td>2</td>\n",
" <td>Yes</td>\n",
" <td>Yes</td>\n",
" <td>27999</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>2</td>\n",
" <td>iPhone 11 Pro Max</td>\n",
" <td>Apple</td>\n",
" <td>iPhone 11 Pro Max</td>\n",
" <td>3969</td>\n",
" <td>6.50</td>\n",
" <td>Yes</td>\n",
" <td>1242</td>\n",
" <td>2688</td>\n",
" <td>6</td>\n",
" <td>...</td>\n",
" <td>12.0</td>\n",
" <td>12.0</td>\n",
" <td>iOS</td>\n",
" <td>Yes</td>\n",
" <td>Yes</td>\n",
" <td>Yes</td>\n",
" <td>2</td>\n",
" <td>Yes</td>\n",
" <td>Yes</td>\n",
" <td>106900</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>3</td>\n",
" <td>iPhone 11</td>\n",
" <td>Apple</td>\n",
" <td>iPhone 11</td>\n",
" <td>3110</td>\n",
" <td>6.10</td>\n",
" <td>Yes</td>\n",
" <td>828</td>\n",
" <td>1792</td>\n",
" <td>6</td>\n",
" <td>...</td>\n",
" <td>12.0</td>\n",
" <td>12.0</td>\n",
" <td>iOS</td>\n",
" <td>Yes</td>\n",
" <td>Yes</td>\n",
" <td>Yes</td>\n",
" <td>2</td>\n",
" <td>Yes</td>\n",
" <td>Yes</td>\n",
" <td>62900</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>4</td>\n",
" <td>LG G8X ThinQ</td>\n",
" <td>LG</td>\n",
" <td>G8X ThinQ</td>\n",
" <td>4000</td>\n",
" <td>6.40</td>\n",
" <td>Yes</td>\n",
" <td>1080</td>\n",
" <td>2340</td>\n",
" <td>8</td>\n",
" <td>...</td>\n",
" <td>12.0</td>\n",
" <td>32.0</td>\n",
" <td>Android</td>\n",
" <td>Yes</td>\n",
" <td>Yes</td>\n",
" <td>Yes</td>\n",
" <td>1</td>\n",
" <td>No</td>\n",
" <td>No</td>\n",
" <td>49990</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>5</td>\n",
" <td>OnePlus 7T</td>\n",
" <td>OnePlus</td>\n",
" <td>7T</td>\n",
" <td>3800</td>\n",
" <td>6.55</td>\n",
" <td>Yes</td>\n",
" <td>1080</td>\n",
" <td>2400</td>\n",
" <td>8</td>\n",
" <td>...</td>\n",
" <td>48.0</td>\n",
" <td>16.0</td>\n",
" <td>Android</td>\n",
" <td>Yes</td>\n",
" <td>Yes</td>\n",
" <td>No</td>\n",
" <td>2</td>\n",
" <td>Yes</td>\n",
" <td>Yes</td>\n",
" <td>34930</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>6</td>\n",
" <td>OnePlus 7T Pro</td>\n",
" <td>OnePlus</td>\n",
" <td>7T Pro</td>\n",
" <td>4085</td>\n",
" <td>6.67</td>\n",
" <td>Yes</td>\n",
" <td>1440</td>\n",
" <td>3120</td>\n",
" <td>8</td>\n",
" <td>...</td>\n",
" <td>48.0</td>\n",
" <td>16.0</td>\n",
" <td>Android</td>\n",
" <td>Yes</td>\n",
" <td>Yes</td>\n",
" <td>Yes</td>\n",
" <td>2</td>\n",
" <td>Yes</td>\n",
" <td>Yes</td>\n",
" <td>52990</td>\n",
" </tr>\n",
" <tr>\n",
" <th>7</th>\n",
" <td>7</td>\n",
" <td>Samsung Galaxy Note 10+</td>\n",
" <td>Samsung</td>\n",
" <td>Galaxy Note 10+</td>\n",
" <td>4300</td>\n",
" <td>6.80</td>\n",
" <td>Yes</td>\n",
" <td>1440</td>\n",
" <td>3040</td>\n",
" <td>8</td>\n",
" <td>...</td>\n",
" <td>12.0</td>\n",
" <td>10.0</td>\n",
" <td>Android</td>\n",
" <td>Yes</td>\n",
" <td>Yes</td>\n",
" <td>Yes</td>\n",
" <td>2</td>\n",
" <td>Yes</td>\n",
" <td>Yes</td>\n",
" <td>79699</td>\n",
" </tr>\n",
" <tr>\n",
" <th>8</th>\n",
" <td>8</td>\n",
" <td>Asus ROG Phone 2</td>\n",
" <td>Asus</td>\n",
" <td>ROG Phone 2</td>\n",
" <td>6000</td>\n",
" <td>6.59</td>\n",
" <td>Yes</td>\n",
" <td>1080</td>\n",
" <td>2340</td>\n",
" <td>8</td>\n",
" <td>...</td>\n",
" <td>48.0</td>\n",
" <td>24.0</td>\n",
" <td>Android</td>\n",
" <td>Yes</td>\n",
" <td>Yes</td>\n",
" <td>Yes</td>\n",
" <td>1</td>\n",
" <td>Yes</td>\n",
" <td>Yes</td>\n",
" <td>37999</td>\n",
" </tr>\n",
" <tr>\n",
" <th>9</th>\n",
" <td>9</td>\n",
" <td>Xiaomi Redmi K20 Pro</td>\n",
" <td>Xiaomi</td>\n",
" <td>Redmi K20 Pro</td>\n",
" <td>4000</td>\n",
" <td>6.39</td>\n",
" <td>Yes</td>\n",
" <td>1080</td>\n",
" <td>2340</td>\n",
" <td>8</td>\n",
" <td>...</td>\n",
" <td>48.0</td>\n",
" <td>20.0</td>\n",
" <td>Android</td>\n",
" <td>Yes</td>\n",
" <td>Yes</td>\n",
" <td>Yes</td>\n",
" <td>2</td>\n",
" <td>No</td>\n",
" <td>No</td>\n",
" <td>23190</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"<p>10 rows × 22 columns</p>\n",
"</div>"
],
"text/plain": [
" Unnamed: 0 Name Brand \\\n",
"0 0 OnePlus 7T Pro McLaren Edition OnePlus \n",
"1 1 Realme X2 Pro Realme \n",
"2 2 iPhone 11 Pro Max Apple \n",
"3 3 iPhone 11 Apple \n",
"4 4 LG G8X ThinQ LG \n",
"5 5 OnePlus 7T OnePlus \n",
"6 6 OnePlus 7T Pro OnePlus \n",
"7 7 Samsung Galaxy Note 10+ Samsung \n",
"8 8 Asus ROG Phone 2 Asus \n",
"9 9 Xiaomi Redmi K20 Pro Xiaomi \n",
"\n",
" Model Battery capacity (mAh) Screen size (inches) \\\n",
"0 7T Pro McLaren Edition 4085 6.67 \n",
"1 X2 Pro 4000 6.50 \n",
"2 iPhone 11 Pro Max 3969 6.50 \n",
"3 iPhone 11 3110 6.10 \n",
"4 G8X ThinQ 4000 6.40 \n",
"5 7T 3800 6.55 \n",
"6 7T Pro 4085 6.67 \n",
"7 Galaxy Note 10+ 4300 6.80 \n",
"8 ROG Phone 2 6000 6.59 \n",
"9 Redmi K20 Pro 4000 6.39 \n",
"\n",
" Touchscreen Resolution x Resolution y Processor ... Rear camera \\\n",
"0 Yes 1440 3120 8 ... 48.0 \n",
"1 Yes 1080 2400 8 ... 64.0 \n",
"2 Yes 1242 2688 6 ... 12.0 \n",
"3 Yes 828 1792 6 ... 12.0 \n",
"4 Yes 1080 2340 8 ... 12.0 \n",
"5 Yes 1080 2400 8 ... 48.0 \n",
"6 Yes 1440 3120 8 ... 48.0 \n",
"7 Yes 1440 3040 8 ... 12.0 \n",
"8 Yes 1080 2340 8 ... 48.0 \n",
"9 Yes 1080 2340 8 ... 48.0 \n",
"\n",
" Front camera Operating system Wi-Fi Bluetooth GPS Number of SIMs 3G \\\n",
"0 16.0 Android Yes Yes Yes 2 Yes \n",
"1 16.0 Android Yes Yes Yes 2 Yes \n",
"2 12.0 iOS Yes Yes Yes 2 Yes \n",
"3 12.0 iOS Yes Yes Yes 2 Yes \n",
"4 32.0 Android Yes Yes Yes 1 No \n",
"5 16.0 Android Yes Yes No 2 Yes \n",
"6 16.0 Android Yes Yes Yes 2 Yes \n",
"7 10.0 Android Yes Yes Yes 2 Yes \n",
"8 24.0 Android Yes Yes Yes 1 Yes \n",
"9 20.0 Android Yes Yes Yes 2 No \n",
"\n",
" 4G/ LTE Price \n",
"0 Yes 58998 \n",
"1 Yes 27999 \n",
"2 Yes 106900 \n",
"3 Yes 62900 \n",
"4 No 49990 \n",
"5 Yes 34930 \n",
"6 Yes 52990 \n",
"7 Yes 79699 \n",
"8 Yes 37999 \n",
"9 No 23190 \n",
"\n",
"[10 rows x 22 columns]"
]
},
"metadata": {},
"output_type": "display_data"
2024-12-06 22:30:14 +04:00
}
],
"source": [
"import pandas as pd\n",
"df = pd.read_csv(\"..//static//csv//ndtv_data_final.csv\")\n",
2024-12-12 15:54:39 +04:00
"print(df.columns)\n",
"display(df.head(10))"
2024-12-06 22:30:14 +04:00
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
2024-12-12 15:54:39 +04:00
"## Регрессия\n",
2024-12-06 22:30:14 +04:00
"\n",
2024-12-12 15:54:39 +04:00
"Цель: Разработать модель регрессии, которая будет предсказывать цену мобильного телефона на основе его технических характеристик и функциональных особенностей.\n",
2024-12-06 22:30:14 +04:00
"\n",
"Применение:\n",
"\n",
2024-12-12 15:54:39 +04:00
"Производители и продавцы мобильных телефонов: Модель может помочь в установлении справедливой цены для новых моделей, основываясь на их технических характеристиках, что может быть полезно для ценообразования и конкуренции на рынке.\n",
2024-12-06 22:30:14 +04:00
"\n",
2024-12-12 15:54:39 +04:00
"Потребители: Модель может помочь пользователям принимать более обоснованные решения при покупке, сравнивая цены и характеристики различных моделей.\n",
2024-12-06 22:30:14 +04:00
"\n",
2024-12-12 15:54:39 +04:00
"Рыночные аналитики: Модель может быть использована для анализа тенденций на рынке мобильных телефонов, выявления факторов, влияющих на цену, и прогнозирования будущих изменений.\n",
"\n",
"Исследования в области технологий: Модель может помочь в изучении влияния различных технических характеристик на цену и популярность моделей."
2024-12-06 22:30:14 +04:00
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
2024-12-12 15:54:39 +04:00
"#### Удаление выбросов"
2024-12-06 22:30:14 +04:00
]
},
{
"cell_type": "code",
"execution_count": 4,
2024-12-06 22:30:14 +04:00
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
2024-12-12 15:54:39 +04:00
"Размер данных до удаления выбросов: (1359, 21)\n",
"Размер данных после удаления выбросов: (1256, 21)\n"
2024-12-06 22:30:14 +04:00
]
}
],
"source": [
"import pandas as pd\n",
2024-12-12 15:54:39 +04:00
"from scipy import stats\n",
2024-12-06 22:30:14 +04:00
"\n",
"# Загружаем набор данных\n",
"df = pd.read_csv(\"..//static//csv//ndtv_data_final.csv\")\n",
"\n",
"# Удаление пустого столбца по имени\n",
"df = df.drop('Unnamed: 0', axis=1)\n",
"\n",
2024-12-12 15:54:39 +04:00
"# Выбор числовых признаков для анализа выбросов\n",
"numeric_features = [\n",
" 'Battery capacity (mAh)', 'Screen size (inches)', 'Resolution x', \n",
" 'Resolution y', 'Processor', 'RAM (MB)', 'Internal storage (GB)', \n",
" 'Rear camera', 'Front camera', 'Number of SIMs', 'Price'\n",
"]\n",
2024-12-06 22:30:14 +04:00
"\n",
2024-12-12 15:54:39 +04:00
"# Вычисление Z-оценок для числовых признаков\n",
"z_scores = stats.zscore(df[numeric_features])\n",
2024-12-06 22:30:14 +04:00
"\n",
2024-12-12 15:54:39 +04:00
"# Определение порога для выбросов\n",
"threshold = 3\n",
2024-12-06 22:30:14 +04:00
"\n",
2024-12-12 15:54:39 +04:00
"# Вывод размеров данных до удаления выбросов\n",
"print(\"Размер данных до удаления выбросов:\", df.shape)\n",
2024-12-06 22:30:14 +04:00
"\n",
2024-12-12 15:54:39 +04:00
"# Удаление строк, содержащих выбросы\n",
"df = df[(z_scores < threshold).all(axis=1)]\n",
2024-12-06 22:30:14 +04:00
"\n",
2024-12-12 15:54:39 +04:00
"# Вывод размеров данных после удаления выбросов\n",
"print(\"Размер данных после удаления выбросов:\", df.shape)"
2024-12-06 22:30:14 +04:00
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
2024-12-12 15:54:39 +04:00
"#### Подготовка данных и оценка базовой модели"
2024-12-06 22:30:14 +04:00
]
},
{
"cell_type": "code",
"execution_count": 5,
2024-12-06 22:30:14 +04:00
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
2024-12-12 15:54:39 +04:00
"Размер обучающей выборки: (1004, 18)\n",
"Размер тестовой выборки: (252, 18)\n",
"Baseline MAE: 4662.689511794094\n",
"Baseline MSE: 50560680.710365206\n",
"Baseline R²: -0.001378207894705552\n"
2024-12-06 22:30:14 +04:00
]
}
],
"source": [
"import pandas as pd\n",
"from sklearn.model_selection import train_test_split\n",
"from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score\n",
"\n",
"\n",
2024-12-12 15:54:39 +04:00
"# Выбор признаков и целевой переменной\n",
"features = [\n",
" 'Brand', 'Battery capacity (mAh)',\n",
" 'Screen size (inches)', 'Touchscreen', 'Resolution x', 'Resolution y',\n",
" 'Processor', 'RAM (MB)', 'Internal storage (GB)', 'Rear camera',\n",
" 'Front camera', 'Operating system', 'Wi-Fi', 'Bluetooth', 'GPS',\n",
" 'Number of SIMs', '3G', '4G/ LTE'\n",
"]\n",
"target = 'Price'\n",
2024-12-08 23:25:41 +04:00
"\n",
2024-12-12 15:54:39 +04:00
"global X_train, X_test, y_train, y_test\n",
"X_train, X_test, y_train, y_test = train_test_split(df[features], df[target], test_size=0.2, random_state=42)\n",
2024-12-08 23:25:41 +04:00
"\n",
2024-12-12 15:54:39 +04:00
"print(\"Размер обучающей выборки:\", X_train.shape)\n",
"print(\"Размер тестовой выборки:\", X_test.shape)\n",
2024-12-06 22:30:14 +04:00
"\n",
2024-12-12 15:54:39 +04:00
"# Базовые предсказания (среднее значение целевой переменной)\n",
"baseline_predictions = [y_train.mean()] * len(y_test)\n",
2024-12-06 22:30:14 +04:00
"\n",
2024-12-12 15:54:39 +04:00
"# Оценка базовой модели\n",
"print('Baseline MAE:', mean_absolute_error(y_test, baseline_predictions))\n",
"print('Baseline MSE:', mean_squared_error(y_test, baseline_predictions))\n",
"print('Baseline R²:', r2_score(y_test, baseline_predictions))"
2024-12-06 22:30:14 +04:00
]
2024-12-08 23:25:41 +04:00
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
2024-12-12 15:54:39 +04:00
"#### Обучение и оценка моделей"
2024-12-08 23:25:41 +04:00
]
},
{
"cell_type": "code",
"execution_count": 6,
2024-12-08 23:25:41 +04:00
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
2024-12-12 15:54:39 +04:00
"Model: Linear Regression trained.\n",
"MAE: 3251.7122571814075\n",
"MSE: 25623200.493888523\n",
"R²: 0.4925203887566195\n",
"--------------------------------------------------\n",
"Model: Decision Tree trained.\n",
"MAE: 4112.809523809524\n",
"MSE: 56543100.29960317\n",
"R²: -0.11986285887206449\n",
"--------------------------------------------------\n",
"Model: Gradient Boosting trained.\n",
"MAE: 2793.2991365668017\n",
"MSE: 23739724.17710429\n",
"R²: 0.5298235285129411\n",
"--------------------------------------------------\n"
2024-12-08 23:25:41 +04:00
]
}
],
"source": [
"import pandas as pd\n",
2024-12-12 15:54:39 +04:00
"from scipy import stats\n",
"from sklearn.model_selection import train_test_split, RandomizedSearchCV\n",
"from sklearn.preprocessing import StandardScaler, OneHotEncoder\n",
2024-12-08 23:25:41 +04:00
"from sklearn.compose import ColumnTransformer\n",
2024-12-12 15:54:39 +04:00
"from sklearn.pipeline import Pipeline\n",
"from sklearn.linear_model import LinearRegression\n",
"from sklearn.tree import DecisionTreeRegressor\n",
"from sklearn.ensemble import GradientBoostingRegressor\n",
2024-12-08 23:25:41 +04:00
"from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score\n",
"\n",
2024-12-12 15:54:39 +04:00
"# Выбор признаков и целевой переменной\n",
"categorical_features = [\n",
" 'Brand', 'Touchscreen', 'Operating system', 'Wi-Fi', \n",
" 'Bluetooth', 'GPS', '3G', '4G/ LTE'\n",
"]\n",
"numeric_features = [\n",
" 'Battery capacity (mAh)', 'Screen size (inches)', 'Resolution x', \n",
" 'Resolution y', 'Processor', 'RAM (MB)', 'Internal storage (GB)', 'Rear camera', \n",
" 'Front camera', 'Number of SIMs'\n",
"]\n",
"target = 'Price'\n",
"\n",
"# Препроцессор для обработки числовых и категориальных признаков\n",
2024-12-08 23:25:41 +04:00
"preprocessor = ColumnTransformer(\n",
" transformers=[\n",
2024-12-12 15:54:39 +04:00
" ('num', StandardScaler(), numeric_features), # Масштабирование числовых признаков\n",
" ('cat', OneHotEncoder(handle_unknown='ignore'), categorical_features) # Однократная кодировка категориальных признаков\n",
" ]\n",
")\n",
"\n",
"# Создание пайплайнов для моделей\n",
"pipeline_linear_regression = Pipeline(steps=[\n",
" ('preprocessor', preprocessor),\n",
" ('regressor', LinearRegression())\n",
"])\n",
"\n",
"pipeline_decision_tree = Pipeline(steps=[\n",
" ('preprocessor', preprocessor),\n",
" ('regressor', DecisionTreeRegressor(random_state=42))\n",
"])\n",
"\n",
"pipeline_gradient_boosting = Pipeline(steps=[\n",
" ('preprocessor', preprocessor),\n",
" ('regressor', GradientBoostingRegressor(random_state=42))\n",
"])\n",
"\n",
"# Список моделей для сравнения\n",
"pipelines = [\n",
" ('Linear Regression', pipeline_linear_regression),\n",
" ('Decision Tree', pipeline_decision_tree),\n",
" ('Gradient Boosting', pipeline_gradient_boosting)\n",
"]\n",
"\n",
"# Обучение моделей и вывод результатов\n",
"for name, pipeline in pipelines:\n",
" pipeline.fit(X_train, y_train)\n",
" predictions = pipeline.predict(X_test)\n",
" print(f\"Model: {name} trained.\")\n",
" print(f\"MAE: {mean_absolute_error(y_test, predictions)}\")\n",
" print(f\"MSE: {mean_squared_error(y_test, predictions)}\")\n",
" print(f\"R²: {r2_score(y_test, predictions)}\")\n",
" print(\"-\" * 50)"
2024-12-08 23:25:41 +04:00
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
2024-12-12 15:54:39 +04:00
"Линейная регрессия улучшила качество предсказаний по сравнению с базовой моделью, но показала меньшую эффективность, чем градиентный бустинг\n",
2024-12-08 23:25:41 +04:00
"\n",
2024-12-12 15:54:39 +04:00
"* MAE уменьшился на 1410.98 (30% улучшение).\n",
2024-12-08 23:25:41 +04:00
"\n",
2024-12-12 15:54:39 +04:00
"* MSE уменьшился на 24937480.22 (49% улучшение).\n",
2024-12-08 23:25:41 +04:00
"\n",
2024-12-12 15:54:39 +04:00
"* R² стал положительным (0.4925), что означает, что модель объясняет 49.25% изменчивости цены.\n",
2024-12-08 23:25:41 +04:00
"\n",
2024-12-12 15:54:39 +04:00
"Дерево решений оказалось наименее эффективным среди всех моделей, показав худшие результаты даже по сравнению с базовой моделью.\n",
2024-12-08 23:25:41 +04:00
"\n",
2024-12-12 15:54:39 +04:00
"* MAE увеличился на 450.12 (9.6% ухудшение).\n",
2024-12-08 23:25:41 +04:00
"\n",
2024-12-12 15:54:39 +04:00
"* MSE увеличился на 5982419.59 (11.8% ухудшение).\n",
2024-12-08 23:25:41 +04:00
"\n",
2024-12-12 15:54:39 +04:00
"* R² стал еще ниже (-0.1199), что указывает на то, что модель работает хуже, чем базовая.\n",
2024-12-08 23:25:41 +04:00
"\n",
2024-12-12 15:54:39 +04:00
"Градиентный бустинг показал лучшие результаты среди всех моделей:\n",
2024-12-08 23:25:41 +04:00
"\n",
2024-12-12 15:54:39 +04:00
"* MAE уменьшился на 1869.39 (40% улучшение) по сравнению с базовой моделью.\n",
"\n",
"* MSE уменьшился на 26820956.53 (53% улучшение) по сравнению с базовой моделью.\n",
2024-12-08 23:25:41 +04:00
"\n",
2024-12-12 15:54:39 +04:00
"* R² достиг 0.5298, что означает, что модель объясняет 52.98% изменчивости цены.\n",
"\n",
"Таким образом, градиентный бустинг является наиболее подходящей моделью для предсказания цены мобильных телефонов на основе выбранных признаков."
2024-12-08 23:25:41 +04:00
]
},
{
2024-12-12 15:54:39 +04:00
"cell_type": "markdown",
2024-12-08 23:25:41 +04:00
"metadata": {},
"source": [
2024-12-12 15:54:39 +04:00
"## Классификация \n",
2024-12-08 23:25:41 +04:00
"\n",
2024-12-12 15:54:39 +04:00
"Цель: Целью классификации является разработка модели, которая будет предсказывать категорию цены мобильного телефона на основе его технических характеристик и функциональных особенностей.\n",
2024-12-08 23:25:41 +04:00
"\n",
2024-12-12 15:54:39 +04:00
"Применение классификации:\n",
2024-12-08 23:25:41 +04:00
"\n",
2024-12-12 15:54:39 +04:00
"1. Рыночная аналитика:\n",
2024-12-08 23:25:41 +04:00
"\n",
2024-12-12 15:54:39 +04:00
"* Помогает производителям и продавцам телефонов определять целевую аудиторию для конкретных моделей.\n",
2024-12-08 23:25:41 +04:00
"\n",
2024-12-12 15:54:39 +04:00
"* Позволяет анализировать конкуренцию в разных ценовых сегментах.\n",
2024-12-08 23:25:41 +04:00
"\n",
2024-12-12 15:54:39 +04:00
"2. Потребительские рекомендации:\n",
2024-12-08 23:25:41 +04:00
"\n",
2024-12-12 15:54:39 +04:00
"* Помогает пользователям выбирать телефоны, соответствующие их бюджету и требованиям.\n",
2024-12-08 23:25:41 +04:00
"\n",
2024-12-12 15:54:39 +04:00
"* Упрощает процесс сравнения телефонов в рамках одной ценовой категории."
2024-12-08 23:25:41 +04:00
]
},
{
"cell_type": "code",
"execution_count": 7,
2024-12-08 23:25:41 +04:00
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
2024-12-12 15:54:39 +04:00
"Размер обучающей выборки: (1004, 18)\n",
"Размер тестовой выборки: (252, 18)\n"
2024-12-08 23:25:41 +04:00
]
}
],
"source": [
"import pandas as pd\n",
2024-12-12 15:54:39 +04:00
"from sklearn.model_selection import train_test_split\n",
2024-12-08 23:25:41 +04:00
"\n",
2024-12-12 15:54:39 +04:00
"# Выбор признаков и целевой переменной\n",
"features = [\n",
" 'Brand', 'Battery capacity (mAh)',\n",
" 'Screen size (inches)', 'Touchscreen', 'Resolution x', 'Resolution y',\n",
" 'Processor', 'RAM (MB)', 'Internal storage (GB)', 'Rear camera',\n",
" 'Front camera', 'Operating system', 'Wi-Fi', 'Bluetooth', 'GPS',\n",
" 'Number of SIMs', '3G', '4G/ LTE'\n",
"]\n",
"target = 'Price'\n",
"\n",
"# Разделение данных на обучающую и тестовую выборки\n",
"X_train, X_test, y_train, y_test = train_test_split(df[features], df[target], test_size=0.2, random_state=42)\n",
"\n",
"print(\"Размер обучающей выборки:\", X_train.shape)\n",
"print(\"Размер тестовой выборки:\", X_test.shape)"
2024-12-08 23:25:41 +04:00
]
},
{
"cell_type": "code",
"execution_count": 8,
2024-12-08 23:25:41 +04:00
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
2024-12-12 15:54:39 +04:00
"PriceCategory\n",
"1 946\n",
"0 946\n",
"Name: count, dtype: int64\n",
"Гиперпараметры для логистической регрессии:\n",
"Accuracy: 0.8760\n",
"Precision: 0.8784\n",
"Recall: 0.8760\n",
"F1-Score: 0.8762\n",
"ROC-AUC: 0.9521\n",
2024-12-12 15:54:39 +04:00
"Гиперпараметры для случайного леса:\n",
"Accuracy: 0.9393\n",
"Precision: 0.9395\n",
"Recall: 0.9393\n",
"F1-Score: 0.9392\n",
"ROC-AUC: 0.9833\n",
"Гиперпараметры для градиентного бустинга:\n",
"Accuracy: 0.9261\n",
"Precision: 0.9261\n",
"Recall: 0.9261\n",
"F1-Score: 0.9261\n",
"ROC-AUC: 0.9777\n",
"\n",
"Результаты моделей:\n",
"\n",
"Logistic Regression:\n",
"Accuracy: 0.8760\n",
"Precision: 0.8784\n",
"Recall: 0.8760\n",
"F1: 0.8762\n",
"Roc_auc: 0.9521\n",
"\n",
"Random Forest:\n",
"Accuracy: 0.9393\n",
"Precision: 0.9395\n",
"Recall: 0.9393\n",
"F1: 0.9392\n",
"Roc_auc: 0.9833\n",
"\n",
"Gradient Boosting:\n",
"Accuracy: 0.9261\n",
"Precision: 0.9261\n",
"Recall: 0.9261\n",
"F1: 0.9261\n",
"Roc_auc: 0.9777\n"
2024-12-08 23:25:41 +04:00
]
}
],
"source": [
"import pandas as pd\n",
2024-12-12 15:54:39 +04:00
"from imblearn.over_sampling import SMOTE\n",
"from sklearn.model_selection import train_test_split\n",
"from sklearn.preprocessing import OneHotEncoder, LabelEncoder\n",
2024-12-08 23:25:41 +04:00
"from sklearn.compose import ColumnTransformer\n",
2024-12-12 15:54:39 +04:00
"from sklearn.pipeline import Pipeline\n",
"from sklearn.preprocessing import StandardScaler\n",
"from sklearn.linear_model import LogisticRegression\n",
"from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier\n",
"from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, roc_auc_score\n",
"from scipy.stats import uniform, randint\n",
"from sklearn.model_selection import RandomizedSearchCV\n",
"\n",
"# Выбор признаков и целевой переменной\n",
"features = [\n",
" 'Brand', 'Battery capacity (mAh)', 'Screen size (inches)', 'Touchscreen', \n",
" 'Resolution x', 'Resolution y', 'Processor', 'RAM (MB)', 'Internal storage (GB)', \n",
" 'Rear camera', 'Front camera', 'Operating system', 'Wi-Fi', 'Bluetooth', 'GPS', \n",
" 'Number of SIMs', '3G', '4G/ LTE'\n",
"]\n",
"target = 'PriceCategory' # Целевая переменная: категория цены\n",
"\n",
"# Преобразование целевой переменной в категории (например, бюджетные, средний класс, премиум)\n",
"bins = [0, 10000, 60000, float('inf')]\n",
2024-12-12 15:54:39 +04:00
"labels = ['Budget', 'Mid-Range', 'Premium']\n",
"df['PriceCategory'] = pd.cut(df['Price'], bins=bins, labels=labels)\n",
"\n",
"# Преобразование категорий в числа\n",
"label_encoder = LabelEncoder()\n",
"df[target] = label_encoder.fit_transform(df[target])\n",
"\n",
"# Определение категориальных и числовых признаков\n",
"categorical_features = [\n",
" 'Brand', 'Touchscreen', 'Operating system', 'Wi-Fi', \n",
" 'Bluetooth', 'GPS', '3G', '4G/ LTE'\n",
"]\n",
"numeric_features = [\n",
" 'Battery capacity (mAh)', 'Processor', 'Screen size (inches)', 'Resolution x', \n",
" 'Resolution y', 'RAM (MB)', 'Internal storage (GB)', 'Rear camera', \n",
" 'Front camera', 'Number of SIMs'\n",
"]\n",
"\n",
"# Препроцессор для обработки числовых и категориальных признаков\n",
"categorical_transformer = Pipeline(steps=[\n",
" ('onehot', OneHotEncoder(handle_unknown='ignore'))\n",
"])\n",
"\n",
"numeric_transformer = Pipeline(steps=[\n",
" ('scaler', StandardScaler())\n",
"])\n",
2024-12-08 23:25:41 +04:00
"\n",
"preprocessor = ColumnTransformer(\n",
" transformers=[\n",
2024-12-12 15:54:39 +04:00
" ('num', numeric_transformer, numeric_features),\n",
" ('cat', categorical_transformer, categorical_features)\n",
2024-12-08 23:25:41 +04:00
" ])\n",
"\n",
2024-12-12 15:54:39 +04:00
"# Применение препроцессора\n",
"X = preprocessor.fit_transform(df[features])\n",
"y = df[target]\n",
"\n",
"# Балансировка классов с помощью SMOTE\n",
"smote = SMOTE(random_state=42)\n",
"X_resampled, y_resampled = smote.fit_resample(X, y)\n",
"\n",
"print(pd.Series(y_resampled).value_counts())\n",
"\n",
"# Разделение данных на обучающую и тестовую выборки\n",
"X_train, X_test, y_train, y_test = train_test_split(X_resampled, y_resampled, test_size=0.2, random_state=42)\n",
"\n",
"# Функция для оценки модели\n",
"def evaluate_model(model, X_test, y_test):\n",
" y_pred = model.predict(X_test)\n",
" y_pred_proba = model.predict_proba(X_test)[:, 1]\n",
2024-12-12 15:54:39 +04:00
" \n",
" accuracy = accuracy_score(y_test, y_pred)\n",
" precision = precision_score(y_test, y_pred, average='weighted') \n",
" recall = recall_score(y_test, y_pred, average='weighted') \n",
" f1 = f1_score(y_test, y_pred, average='weighted') \n",
" roc_auc = roc_auc_score(y_test, y_pred_proba, multi_class='ovr')\n",
" \n",
" print(f\"Accuracy: {accuracy:.4f}\")\n",
" print(f\"Precision: {precision:.4f}\")\n",
" print(f\"Recall: {recall:.4f}\")\n",
" print(f\"F1-Score: {f1:.4f}\")\n",
" print(f\"ROC-AUC: {roc_auc:.4f}\")\n",
" \n",
" return {\n",
" 'accuracy': accuracy,\n",
" 'precision': precision,\n",
" 'recall': recall,\n",
" 'f1': f1,\n",
" 'roc_auc': roc_auc\n",
" }\n",
"\n",
"# Логистическая регрессия\n",
"print(\"Гиперпараметры для логистической регрессии:\")\n",
"logreg_param_dist = {\n",
" 'classifier__C': uniform(loc=0, scale=4),\n",
" 'classifier__penalty': ['l1', 'l2'],\n",
" 'classifier__solver': ['liblinear', 'saga']\n",
2024-12-08 23:25:41 +04:00
"}\n",
"\n",
2024-12-12 15:54:39 +04:00
"logreg_pipeline = Pipeline([\n",
" ('classifier', LogisticRegression(max_iter=1000, random_state=42))\n",
"])\n",
"\n",
"logreg_random_search = RandomizedSearchCV(logreg_pipeline, param_distributions=logreg_param_dist, n_iter=50, cv=5, random_state=42, n_jobs=-1)\n",
"logreg_random_search.fit(X_train, y_train)\n",
"logreg_best_model = logreg_random_search.best_estimator_\n",
"logreg_results = evaluate_model(logreg_best_model, X_test, y_test)\n",
"\n",
"# Случайный лес\n",
"print(\"Гиперпараметры для случайного леса:\")\n",
"rf_param_dist = {\n",
" 'classifier__n_estimators': randint(100, 1000),\n",
" 'classifier__max_depth': [None] + list(randint(10, 100).rvs(10)),\n",
" 'classifier__min_samples_split': randint(2, 20),\n",
" 'classifier__min_samples_leaf': randint(1, 20),\n",
" 'classifier__bootstrap': [True, False]\n",
2024-12-08 23:25:41 +04:00
"}\n",
"\n",
2024-12-12 15:54:39 +04:00
"rf_pipeline = Pipeline([\n",
" ('classifier', RandomForestClassifier(random_state=42))\n",
"])\n",
"\n",
"rf_random_search = RandomizedSearchCV(rf_pipeline, param_distributions=rf_param_dist, n_iter=50, cv=5, random_state=42, n_jobs=-1)\n",
"rf_random_search.fit(X_train, y_train)\n",
"rf_best_model = rf_random_search.best_estimator_\n",
"rf_results = evaluate_model(rf_best_model, X_test, y_test)\n",
"\n",
"# Градиентный бустинг\n",
"print(\"Гиперпараметры для градиентного бустинга:\")\n",
"gb_param_dist = {\n",
" 'classifier__n_estimators': randint(100, 1000),\n",
" 'classifier__learning_rate': uniform(0.01, 0.5),\n",
" 'classifier__max_depth': [None] + list(randint(10, 100).rvs(10)),\n",
" 'classifier__min_samples_split': randint(2, 20),\n",
" 'classifier__min_samples_leaf': randint(1, 20),\n",
" 'classifier__subsample': uniform(0.5, 0.5)\n",
"}\n",
2024-12-08 23:25:41 +04:00
"\n",
2024-12-12 15:54:39 +04:00
"gb_pipeline = Pipeline([\n",
" ('classifier', GradientBoostingClassifier(random_state=42))\n",
"])\n",
2024-12-08 23:25:41 +04:00
"\n",
2024-12-12 15:54:39 +04:00
"gb_random_search = RandomizedSearchCV(gb_pipeline, param_distributions=gb_param_dist, n_iter=50, cv=5, random_state=42, n_jobs=-1)\n",
"gb_random_search.fit(X_train, y_train)\n",
"gb_best_model = gb_random_search.best_estimator_\n",
"gb_results = evaluate_model(gb_best_model, X_test, y_test)\n",
2024-12-08 23:25:41 +04:00
"\n",
2024-12-12 15:54:39 +04:00
"# Вывод результатов\n",
"print(\"\\nРезультаты моделей:\")\n",
"print(\"\\nLogistic Regression:\")\n",
"for metric, value in logreg_results.items():\n",
" print(f\"{metric.capitalize()}: {value:.4f}\")\n",
2024-12-08 23:25:41 +04:00
"\n",
2024-12-12 15:54:39 +04:00
"print(\"\\nRandom Forest:\")\n",
"for metric, value in rf_results.items():\n",
" print(f\"{metric.capitalize()}: {value:.4f}\")\n",
2024-12-08 23:25:41 +04:00
"\n",
2024-12-12 15:54:39 +04:00
"print(\"\\nGradient Boosting:\")\n",
"for metric, value in gb_results.items():\n",
" print(f\"{metric.capitalize()}: {value:.4f}\")"
2024-12-08 23:25:41 +04:00
]
},
{
"cell_type": "code",
"execution_count": 46,
2024-12-08 23:25:41 +04:00
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Logistic Regression Metrics:\n",
"Accuracy: 0.8760\n",
"Precision: 0.8784\n",
"Recall: 0.8760\n",
"F1-Score: 0.8762\n",
"ROC-AUC: 0.9521\n"
2024-12-08 23:25:41 +04:00
]
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 640x480 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Random Forest Metrics:\n",
"Accuracy: 0.9393\n",
"Precision: 0.9395\n",
"Recall: 0.9393\n",
"F1-Score: 0.9392\n",
"ROC-AUC: 0.9833\n"
]
},
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAi8AAAHHCAYAAAB3K7g2AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAAA92ElEQVR4nO3dd3gU5f7+8XsT0itIQgAhhSC9NwFpglIEwYiIiCYUEZReBPQoRZqAdEWQQxWliFLkqEhTwRxAIAEpAtIU6UhJA5LM7w9+2S9LCtmQsAzn/bquXGafeWb2M5PB3HnmmVmLYRiGAAAATMLJ0QUAAADYg/ACAABMhfACAABMhfACAABMhfACAABMhfACAABMhfACAABMhfACAABMhfACAABMhfCC/wmHDx/W008/LT8/P1ksFq1cuTJXt3/8+HFZLBbNnz8/V7drZg0bNlTDhg1zbXtxcXHq2rWrgoKCZLFY1Ldv31zbtllwngG3EF5w3/zxxx96/fXXFRYWJnd3d/n6+qpu3bqaOnWqEhMT8/S9IyMjtXfvXo0ePVqLFi1S9erV8/T97qeoqChZLBb5+vpmeBwPHz4si8Uii8WiiRMn2r39v//+W8OHD1dMTEwuVJtzY8aM0fz589WjRw8tWrRIr7zySp6+X0hIiPW4WSwWeXl5qWbNmlq4cGGevq/Z3Hmcbv9KSkpydHnp/PLLLxo+fLguX77s6FJwD/I5ugD8b1i7dq1eeOEFubm56dVXX1X58uV148YNbdmyRYMGDdK+ffs0e/bsPHnvxMRERUdH65133lHPnj3z5D2Cg4OVmJgoFxeXPNn+3eTLl08JCQlas2aN2rVrZ7Ns8eLFcnd3z/Evkr///lsjRoxQSEiIKleunO311q1bl6P3y8zGjRv1+OOPa9iwYbm63axUrlxZAwYMkCSdPn1ac+bMUWRkpK5fv67XXnvtvtXxoLv9ON3O1dXVAdVk7ZdfftGIESMUFRUlf39/R5eDHCK8IM8dO3ZM7du3V3BwsDZu3KjChQtbl7355ps6cuSI1q5dm2fvf/78eUnK0/9RWSwWubu759n278bNzU1169bVF198kS68fP7553rmmWe0YsWK+1JLQkKCPD09c/0X17lz51S2bNlc215ycrJSU1OzrLNo0aLq2LGj9XVUVJTCwsI0efJkwstt7jxOuSU1NVU3btxw6L8tPJi4bIQ8N378eMXFxenf//63TXBJEx4erj59+lhfJycn6/3331eJEiXk5uamkJAQvf3227p+/brNeiEhIWrZsqW2bNmimjVryt3dXWFhYTbD+sOHD1dwcLAkadCgQbJYLAoJCZF06xdR2ve3Gz58uCwWi03bDz/8oCeeeEL+/v7y9vZWqVKl9Pbbb1uXZzYXYePGjapXr568vLzk7++v1q1b68CBAxm+35EjR6x/Dfr5+alTp05KSEjI/MDeoUOHDvr2229thsN37Nihw4cPq0OHDun6X7p0SQMHDlSFChXk7e0tX19fNW/eXLGxsdY+mzdvVo0aNSRJnTp1sl4OSNvPhg0bqnz58tq5c6fq168vT09P63G5c85LZGSk3N3d0+1/06ZNlT9/fv39998Z7tfmzZtlsVh07NgxrV271lrD8ePHJd0KNV26dFGhQoXk7u6uSpUqacGCBTbbSPv5TJw4UVOmTLGeW/v378/WsU0TEBCg0qVL648//rBp//nnn/XCCy+oePHicnNzU7FixdSvX790l/GioqLk7e2tU6dOqU2bNvL29lZAQIAGDhyolJQUm76XL19WVFSU/Pz85O/vr8jIyEwvddhznh06dEgdO3aUn5+fAgIC9O6778owDP35559q3bq1fH19FRQUpA8//NCuY5OV+Ph4DRgwQMWKFZObm5tKlSqliRMnyjAMm34Wi0U9e/bU4sWLVa5cObm5uem7776TJJ06dUqdO3dWoUKF5ObmpnLlymnu3Lnp3mv69OkqV66cPD09lT9/flWvXl2ff/659RgMGjRIkhQaGpruXIJ5MPKCPLdmzRqFhYWpTp062erftWtXLViwQG3bttWAAQO0bds2jR07VgcOHNDXX39t0/fIkSNq27atunTposjISM2dO1dRUVGqVq2aypUrp4iICPn7+6tfv3566aWX1KJFC3l7e9tV/759+9SyZUtVrFhRI0eOlJubm44cOaKtW7dmud769evVvHlzhYWFafjw4UpMTNT06dNVt25d7dq1K11wateunUJDQzV27Fjt2rVLc+bMUWBgoD744INs1RkREaHu3bvrq6++UufOnSXdGnUpXbq0qlatmq7/0aNHtXLlSr3wwgsKDQ3V2bNnNWvWLDVo0ED79+9XkSJFVKZMGY0cOVLvvfeeunXrpnr16kmSzc/y4sWLat68udq3b6+OHTuqUKFCGdY3depUbdy4UZGRkYqOjpazs7NmzZqldevWadGiRSpSpEiG65UpU0aLFi1Sv3799Oijj1ovTwQEBCgxMVENGzbUkSNH1LNnT4WGhmr58uWKiorS5cuXbUKxJM2bN09JSUnq1q2b3NzcVKBAgWwd2zTJycn666+/lD9/fpv25cuXKyEhQT169NAjjzyi7du3a/r06frrr7+0fPlym74pKSlq2rSpatWqpYkTJ2r9+vX68MMPVaJECfXo0UOSZBiGWrdurS1btqh79+4qU6aMvv76a0VGRqaryd7z7MUXX1SZMmU0btw4rV27VqNGjVKBAgU0a9YsPfnkk/rggw+0ePFiDRw4UDVq1FD9+vXvelxu3rypCxcu2LR5enrK09NThmHo2Wef1aZNm9SlSxdVrlxZ33//vQYNGqRTp05p8uTJNutt3LhRy5YtU8+ePVWwYEGFhITo7Nmzevzxx63hJiAgQN9++626dOmiq1evWidvf/rpp+rdu7fatm2rPn36KCkpSXv27NG2bdvUoUMHRURE6NChQ/riiy80efJkFSxYUNKtcwkmYwB56MqVK4Yko3Xr1tnqHxMTY0gyunbtatM+cOBAQ5KxceNGa1twcLAhyfjpp5+sbefOnTPc3NyMAQMGWNuOHTtmSDImTJhgs83IyEgjODg4XQ3Dhg0zbv+nMXnyZEOScf78+UzrTnuPefPmWdsqV65sBAYGGhcvXrS2xcbGGk5OTsarr76a7v06d+5ss83nnnvOeOSRRzJ9z9v3w8vLyzAMw2jbtq3RuHFjwzAMIyUlxQgKCjJGjBiR4TFISkoyUlJS0u2Hm5ubMXLkSGvbjh070u1bmgYNGhiSjE8++STDZQ0aNLBp+/777w1JxqhRo4yjR48a3t7eRps2be66j4Zx6+f9zDPP2LRNmTLFkGR89tln1rYbN24YtWvXNry9vY2rV69a90uS4evra5w7dy7b7/f0008b58+fN86fP2/s3bvXeOWVVwxJxptvvmnTNyEhId36Y8eONSwWi3HixAlrW2RkpCHJ5vgahmFUqVLFqFatmvX1ypUrDUnG+PHjrW3JyclGvXr17vk869atm802H330UcNisRjjxo2ztv/zzz+Gh4eHERkZma3jJCnd17Bhw2z2ZdSoUTbrtW3b1rBYLMaRI0esbZIMJycnY9++fTZ9u3TpYhQuXNi4cOGCTXv79u0NPz8/6/Fv3bq1Ua5cuSzrnTBhgiHJOHbs2F33DQ8uLhshT129elWS5OPjk63+//nPfyRJ/fv3t2lP+2v7zrkxZcuWtY4GSLf+gipVqpSOHj2a45rvlDZXZtWqVUpNTc3WOqdPn1ZMTIyioqJs/rqvWLGinnrqKet+3q579+42r+vVq6eLFy9aj2F2dOjQQZs3b9aZM2e0ceNGnTlzJsNLRtKteTJOTrf+F5CSkqKLFy9aL4nt2rUr2+/p5uamTp06Zavv008/rddff10jR45URESE3N3dNWvWrGy/153+85//KCgoSC+99JK1zcXFRb1791ZcXJx+/PFHm/7PP/+8XX9lr1u3TgEBAQoICFCFChW0aNEiderUSRMmTLDp5+HhYf0+Pj5eFy5cUJ06dWQYhnbv3p1uuxn9rG8/Z//zn/8oX7581pEYSXJ2dlavXr1
"text/plain": [
"<Figure size 640x480 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Gradient Boosting Metrics:\n",
"Accuracy: 0.9261\n",
"Precision: 0.9261\n",
"Recall: 0.9261\n",
"F1-Score: 0.9261\n",
"ROC-AUC: 0.9777\n"
]
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 640x480 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
2024-12-08 23:25:41 +04:00
}
],
"source": [
2024-12-12 15:54:39 +04:00
"import seaborn as sns\n",
2024-12-08 23:25:41 +04:00
"import matplotlib.pyplot as plt\n",
2024-12-12 15:54:39 +04:00
"from sklearn.metrics import confusion_matrix, roc_curve, auc, roc_auc_score, accuracy_score, precision_score, recall_score, f1_score\n",
"from sklearn.preprocessing import label_binarize\n",
"import numpy as np\n",
"\n",
"# Функция для построения матрицы ошибок\n",
2024-12-12 15:54:39 +04:00
"def plot_confusion_matrix(y_true, y_pred, title):\n",
" cm = confusion_matrix(y_true, y_pred)\n",
" sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', cbar=False)\n",
" plt.title(title)\n",
" plt.xlabel('Предсказанные значения')\n",
" plt.ylabel('Истинные значения')\n",
" plt.show()\n",
"\n",
"# Функция для оценки и визуализации модели\n",
2024-12-12 15:54:39 +04:00
"def evaluate_and_plot_model(model, X_test, y_test, model_name, class_names):\n",
" y_pred = model.predict(X_test)\n",
" y_pred_proba = model.predict_proba(X_test)[:, 1]\n",
2024-12-12 15:54:39 +04:00
" # Метрики\n",
" accuracy = accuracy_score(y_test, y_pred)\n",
" precision = precision_score(y_test, y_pred, average='weighted')\n",
" recall = recall_score(y_test, y_pred, average='weighted')\n",
" f1 = f1_score(y_test, y_pred, average='weighted')\n",
" roc_auc = roc_auc_score(y_test, y_pred_proba, multi_class='ovr', average='weighted')\n",
" \n",
" print(f\"{model_name} Metrics:\")\n",
" print(f\"Accuracy: {accuracy:.4f}\")\n",
" print(f\"Precision: {precision:.4f}\")\n",
" print(f\"Recall: {recall:.4f}\")\n",
" print(f\"F1-Score: {f1:.4f}\")\n",
" print(f\"ROC-AUC: {roc_auc:.4f}\")\n",
" \n",
" # Визуализация\n",
" plot_confusion_matrix(y_test, y_pred, f'Confusion Matrix for {model_name}')\n",
"\n",
"# Пример использования\n",
"class_names = ['Budget', 'Mid-Range', 'Premium']\n",
2024-12-12 15:54:39 +04:00
"evaluate_and_plot_model(logreg_best_model, X_test, y_test, 'Logistic Regression', class_names)\n",
"evaluate_and_plot_model(rf_best_model, X_test, y_test, 'Random Forest', class_names)\n",
"evaluate_and_plot_model(gb_best_model, X_test, y_test, 'Gradient Boosting', class_names)"
2024-12-08 23:25:41 +04:00
]
2024-12-06 22:30:14 +04:00
}
],
"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
}