{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "2PQW7OXEoWEZ"
},
"source": [
"# Введение в анализ данных\n",
"## Домашнее задание 3, сложная часть. Линейная и логистическая регрессии.\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "aRt8VO2EoWEa"
},
"source": [
"**Правила, прочитайте внимательно:**\n",
"\n",
"* Выполненную работу нужно отправить телеграм-боту `@thetahat_ds25_bot`. Для начала работы с ботом каждый раз отправляйте `/start`. Дождитесь подтверждения от бота, что он принял файл. Если подтверждения нет, то что-то не так. **Работы, присланные иным способом, не принимаются.**\n",
"* Дедлайн см. в боте. После дедлайна работы не принимаются кроме случаев наличия уважительной причины.\n",
"* Прислать нужно **ноутбук в формате `ipynb`**. Если вы строите интерактивные графики, их стоит прислать в формате html.\n",
"* Следите за размером файлов. **Бот не может принимать файлы весом более 20 Мб.** Если файл получается больше, заранее разделите его на несколько.\n",
"* Выполнять задание необходимо полностью самостоятельно. **При обнаружении списывания всем участникам списывания дается штраф -2 балла к итоговой оценке за семестр.**\n",
"* Решения, размещенные на каких-либо интернет-ресурсах, не принимаются. Кроме того, публикация решения в открытом доступе может быть приравнена к предоставлении возможности списать.\n",
"* Обратите внимание на правила использования ИИ-инструментов при решении домашнего задания.\n",
"* **Код из рассказанных на занятиях ноутбуков** можно использовать без ограничений.\n",
"* Для выполнения задания используйте этот ноутбук в качестве основы, ничего не удаляя из него. Можно добавлять необходимое количество ячеек.\n",
"* Комментарии к решению пишите в markdown-ячейках.\n",
"* Выполнение задания (ход решения, выводы и пр.) должно быть осуществлено на русском языке.\n",
"* Решение проверяется системой ИИ-проверки
**ThetaGrader**. Результат проверки валидируется и исправляется человеком, после чего комментарии отправляются студентам.\n",
"* Если код будет не понятен проверяющему, оценка может быть снижена.\n",
"* Никакой код из данного задания при проверке запускаться не будет. *Если код студента не выполнен, недописан и т.д., то он не оценивается.*\n",
"* **Код из рассказанных на занятиях ноутбуков** можно использовать без ограничений.\n",
"\n",
"**Правила оформления теоретических задач:**\n",
"\n",
"* Решения необходимо оформить в виде $\\LaTeX$ в markdown-ячейках. Иные способы (в т.ч. фотографии) не принимаются.\n",
"* Если вы не знаете $\\LaTeX$, используйте ИИ-инструменты для оформления черновика решения. Примеры были показаны на лекции 2 по ИИ-инструментам.\n",
"* **В решениях поясняйте, чем вы пользуетесь**, хотя бы кратко. \n",
"* Решение, в котором есть только ответ, и отсутствуют вычисления, оценивается в 0 баллов.\n",
"\n",
"\n",
"Важно!!! Правила заполнения ноутбука:\n",
"* Запрещается удалять имеющиеся в ноутбуке ячейки, менять местами положения задач.\n",
"* Сохраняйте естественный линейный порядок повествования в ноутбуке сверху-вниз.\n",
"* Отвечайте на вопросы, а также добавляйте новые ячейки в предложенных местах, которые обозначены `<...>`.\n",
"* В markdown-ячейка, содержащих описание задачи, находятся специальные отметки, которые запрещается модифицировать.\n",
"* При нарушении данных правил работа может получить 0 баллов.\n",
"\n",
"\n",
"**Баллы за задание:**\n",
"\n",
"Легкая часть (достаточно на \"хор\"):\n",
"\n",
"* Задачи 1-4: скачайте первый ноутбук с условием задания со страницы курса.\n",
"\n",
"Сложная часть (необходимо на \"отл\"):\n",
"\n",
"* Задача 5 — 80 баллов;\n",
"* Задача 6 — 70 баллов;\n",
"* Задача 7 — 50 баллов.\n",
"\n",
"Баллы учитываются в обязательной части курса и не влияют на оценку по факультативной части."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "TLUn-L0HoWEb"
},
"outputs": [],
"source": [
"# Bot check\n",
"\n",
"# HW_ID: fpmi_ad3_part2\n",
"# Бот проверит этот ID и предупредит, если случайно сдать что-то не то.\n",
"\n",
"# Status: not final\n",
"# Перед отправкой в финальном решении удали \"not\" в строчке выше.\n",
"# Так бот проверит, что ты отправляешь финальную версию, а не промежуточную.\n",
"# Никакие значения в этой ячейке не влияют на факт сдачи работы."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "LjG63iFWoWEb"
},
"outputs": [],
"source": [
"import numpy as np\n",
"import pandas as pd\n",
"import seaborn as sns\n",
"from typing import Literal\n",
"\n",
"sns.set(style=\"whitegrid\", palette=\"Set2\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "4TDjFMbboWEc"
},
"source": [
"При решении задания используйте `sklearn`. Пропишите сюда необходимые импорты"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "j19vAJp2oWEc"
},
"outputs": [],
"source": [
"from sklearn.base import BaseEstimator\n",
"from sklearn.preprocessing import StandardScaler\n",
"\n",
"..."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "N5pKs47noWEc"
},
"source": [
"---\n",
"### Легкая часть\n",
"\n",
"Задачи 1-4: скачайте первый ноутбук с условием задания со страницы курса."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n",
"### Сложная часть"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "9T8Ypp5frPWw"
},
"source": [
"---\n",
"### Задача 5."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "rHtqkeInrWZw"
},
"source": [
"\n",
"\n",
"**1.** Реализуйте логистическую регрессию для двух вариантов поиска оценки параметров:\n",
"* простой градиентный спуск;\n",
"* стохастический градиентный спуск с `batch_size` элементами на каждой итерации.\n",
"\n",
"Останавливайте итерации при выполнении хотя бы одного из двух условий:\n",
"* количество итераций превзошло число `max_iter`;\n",
"* оптимизируемый функционал изменился за итерацию не более чем на `tol`.\n",
"\n",
"При выполнении каждой итерации с целью дальнейшего анализа сохраняйте текущее значение оптимизируемого функционала, а также затраченное время на итерацию. **При реализации класса запрещено пользоваться ИИ-инструментами.**\n",
"\n",
"*Замечания.*\n",
"\n",
"1. Для чистоты эксперимента время шага внутри цикла нужно замерять от конца предыдущего шага до конца текущего, а не от начала текущего шага. Время измеряйте с помощью `from time import time`.\n",
"\n",
"2. Иногда при подсчете сигмоиды и оптимизируемого функционала могут возникать вычислительные ошибки. Для их избежания существуют специальные трюки.\n",
" * [How to Evaluate the Logistic Loss and not NaN trying](http://fa.bianp.net/blog/2019/evaluate_logistic/)\n",
" * [Exp-normalize trick](https://timvieira.github.io/blog/post/2014/02/11/exp-normalize-trick/)
\n",
"3. Трюки не обязательно реализовывать самостоятельно, можете воспользоваться функциями для них из `numpy` или `scipy`:\n",
" * [`numpy.logaddexp`](https://numpy.org/doc/stable/reference/generated/numpy.logaddexp.html);\n",
" * [`scipy.special.logsumexp`](https://docs.scipy.org/doc/scipy/reference/generated/scipy.special.logsumexp.html).\n",
"4. Обратите внимание, что класс `LogisticRegression` — наследник класса `BaseEstimator`, это с легкостью позволит использовать наш класс в различных пайплайнах библиотеки `sklearn`.\n",
"4. Следите за качеством кода, комментируйте логические этапы кода. Несоблюдение этого требования может привести к потере баллов.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# При реализации класса запрещено пользоваться ИИ-инструментами.\n",
"\n",
"\n",
"class LogisticRegression(BaseEstimator):\n",
" \"\"\"Модель логистической регрессии.\n",
"\n",
" Параметры:\n",
" method (Literal['gd', 'sgd']): Метод оптимизации ('gd' - градиентный спуск, \n",
" 'sgd' - стохастический градиентный спуск).\n",
" learning_rate (float): Константа скорости обучения, на которую домножаем градиент при обучении\n",
" tol (float): Допустимое изменение функционала между итерациями.\n",
" max_iter (int): Максимальное число итераций.\n",
" batch_size (int): Размер выборки для оценки градиента (используется только при 'sgd').\n",
" fit_intercept (bool): Добавлять ли константу в признаки.\n",
" save_history (bool): Сохранять ли историю обучения.\n",
" \"\"\"\n",
"\n",
" def __init__(\n",
" self,\n",
" method: Literal[\"gd\", \"sgd\"] = \"gd\",\n",
" learning_rate: float = 0.5,\n",
" tol: float = 1e-3,\n",
" max_iter: int = int(1e4),\n",
" batch_size: int = 64,\n",
" fit_intercept: bool = True,\n",
" save_history: bool = True,\n",
" ):\n",
" \"\"\"Создает модель и инициализирует параметры.\"\"\"\n",
" self.method = method\n",
" self.learning_rate = learning_rate\n",
" self.tol = tol\n",
" self.max_iter = max_iter\n",
" self.batch_size = batch_size\n",
" self.fit_intercept = fit_intercept\n",
" self.save_history = save_history\n",
" self.history = [] # История обучения\n",
"\n",
" @staticmethod\n",
" def _sigmoid(x: np.ndarray) -> np.ndarray:\n",
" \"\"\"Вычисляет сигмоидную функцию.\"\"\"\n",
" return 1 / (1 + np.exp(-x))\n",
"\n",
" def _add_intercept(self, X: np.ndarray) -> np.ndarray:\n",
" \"\"\"Добавляет свободный коэффициент к матрице признаков.\n",
"\n",
" Параметры: X (np.ndarray): Исходная матрица признаков.\n",
"\n",
" Возвращает: np.ndarray: Матрица X с добавленным свободным\n",
" коэффициентом.\n",
" \"\"\"\n",
" X_copy = np.full((X.shape[0], X.shape[1] + 1), fill_value=1)\n",
" X_copy[:, :-1] = X\n",
" return X_copy\n",
"\n",
" def fit(self, X: np.ndarray, Y: np.ndarray) -> \"LogisticRegression\":\n",
" \"\"\"Обучает модель логистической регрессии.\n",
"\n",
" Также, в случае self.save_history=True, добавляет в self.history\n",
" текущее значение оптимизируемого функционала и затраченное время.\n",
"\n",
" Параметры:\n",
" X (np.ndarray): Матрица признаков.\n",
" Y (np.ndarray): Вектор истинных меток.\n",
"\n",
" Возвращает:\n",
" LogisticRegression: Обученная модель.\n",
" \"\"\"\n",
" if X.shape[0] != Y.shape[0]:\n",
" raise ValueError(\"Количество строк в X и Y должно совпадать\")\n",
"\n",
" if self.fit_intercept:\n",
" X_copy = self._add_intercept(X)\n",
" else:\n",
" X_copy = X.copy()\n",
"\n",
" ...\n",
"\n",
" self.coef_ = ... # Коэффициенты модели\n",
" self.intercept_ = ... # Свободный коэффициент\n",
" self.n_iter_ = ... # Число итераций\n",
"\n",
" return self\n",
"\n",
" def predict(self, X: np.ndarray) -> np.ndarray:\n",
" \"\"\"Возвращает предсказанные классы.\n",
"\n",
" Параметры: X (np.ndarray): Матрица признаков.\n",
"\n",
" Возвращает: np.ndarray: Предсказанные классы.\n",
" \"\"\"\n",
" if self.fit_intercept:\n",
" X_copy = self._add_intercept(X)\n",
" else:\n",
" X_copy = X.copy()\n",
"\n",
" if X_copy.shape[1] != self.coef_.shape[0]:\n",
" raise ValueError(\"Число признаков в X не соответствует числу коэффициентов модели\")\n",
"\n",
" ...\n",
" return predictions\n",
"\n",
" def predict_proba(self, X: np.ndarray) -> np.ndarray:\n",
" \"\"\"Возвращает вероятности классов 0 и 1.\n",
"\n",
" Параметры: X (np.ndarray): Матрица признаков.\n",
"\n",
" Возвращает: np.ndarray: Матрица вероятностей классов (n_samples,\n",
" 2).\n",
" \"\"\"\n",
" if self.fit_intercept:\n",
" X_copy = self._add_intercept(X)\n",
" else:\n",
" X_copy = X.copy()\n",
"\n",
" if X_copy.shape[1] != self.coef_.shape[0]:\n",
" raise ValueError(\"Число признаков в X не соответствует числу коэффициентов модели\")\n",
"\n",
" ...\n",
" return prob_predictions"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "UdI6YePO7KD4"
},
"source": [
"\n",
"\n",
"Рассмотрим датасет [Diabetes Health Indicators](https://www.kaggle.com/datasets/alexteboul/diabetes-health-indicators-dataset).\n",
"\n",
"**Для данного задания будем рассматривать версию датасета** `diabetes_binary_5050split_health_indicators_BRFSS2015.csv`\n",
"\n",
"\n",
"Этот датасет содержит статистику здравоохранения и информацию об образе жизни, полученную в результате опросов вместе с меткой наличия/отсутствия диабета у участников. Среди признаков есть демографические данные, результаты лабораторных тестов и ответы на вопросы анкеты. Целевая переменная `Diabetes_binary` определяет статус пациента: есть ли у него диабет или предиабет (`1`), или он здоров (`0`).\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "uaTsecV5Sjkl"
},
"source": [
"Рассмотрим некоторые признаки, представленные в датасете.\n",
"\n",
"**Показатели здоровья**\n",
"\n",
"- `HighBP`: Высокое кровяное давление (`1` = да, `0` = нет).\n",
"\n",
"- `HighChol`: Высокий уровень холестерина (`1` = да, `0` = нет).\n",
"\n",
"- `CholCheck`: Проверка уровня холестерина за последние 5 лет (`1` = да, `0` = нет).\n",
"\n",
"- `BMI`: Индекс массы тела (рассчитывается как вес (кг) / рост² (м²)).\n",
"\n",
"- `GenHlth`: Общая оценка здоровья (`1` = отличное, `2` = очень хорошее, ..., `5` = плохое).\n",
"\n",
"**Образ жизни**\n",
"- `Smoker`: Статус курения (`1` = выкурил ≥100 сигарет за жизнь, `0` = нет).\n",
"\n",
"- `PhysActivity`: Физическая активность вне работы (`1` = да, `0` = нет).\n",
"\n",
"- `Fruits`: Регулярное употребление фруктов (`1` = не менее 1 раз в день, `0` = реже).\n",
"\n",
"**Доступ к медицине**\n",
"- `AnyHealthcare`: Наличие медицинской страховки (`1` = да, `0` = нет).\n",
"\n",
"- `NoDocbcCost`: Отказ от визита к врачу из-за стоимости (`1` = да, `0` = нет).\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Скачайте файл и прочитайте его с помощью `pandas`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "cEgtTimdrasr"
},
"outputs": [],
"source": [
"dataset = pd.read_csv(\"diabets_health_indicators.csv\")\n",
"dataset.head()"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "ZIobQynHrlID"
},
"source": [
"\n",
"\n",
"Разделите выборку на обучающую и тестовую и выполните преобразование категориальных признаков."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "x_dPlSZdrma4"
},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "mB_9uDuArn8M"
},
"source": [
"Для интерпретации коэффициентов необходимо нормализовать данные. Воспользуемся для этого классом `StandardScaler` из библиотеки `sklearn`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "6K8fHeL1roRf"
},
"outputs": [],
"source": [
"scaler = StandardScaler()\n",
"..."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"\n",
"**2.** Обучите две модели логистической регрессии с помощью методов\n",
"* простой градиентный спуск;\n",
"* стохастический градиентный спуск."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "_CokLOd9rp8_"
},
"source": [
"Постройте график, на котором нанесите две кривые обучения, каждая из которых отображает зависимость оптимизируемого функционала от номера итерации метода. **Функционал должен быть одинаковый для всех моделей**. Нарисуйте также график зависимости этого функционала от времени работы метода. \n",
"\n",
"*Замечания:*\n",
"* Все графики должны быть информативны, с подписанными осями и т.д..\n",
"* Для чистоты эксперимента желательно не запускать в момент обучения другие задачи и провести обучение несколько раз, усреднив результаты."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Сделайте выводы. Что будет при обучении на датасете, если увеличить количество объектов, а число признаков оставить прежним?"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "eQAaaOUdruoc"
},
"source": [
"..."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "CRk5SvBrrzGo"
},
"source": [
"\n",
"\n",
"**3.** Исследуйте влияние размер шага (`learning_rate`) на качество модели для двух режимов обучения (простой и стохастический градиентный спуск). Для каждого размера шага получите качество модели при использовании простого и стохастического градиентного спуска. Сравните качество полученных моделей по метрике `accuracy`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "pHHtsgd0r53G"
},
"outputs": [],
"source": [
"learning_rate_list = np.logspace(-5, 3, 8)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Kgz4aaFRyJHe"
},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Сделайте выводы"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"..."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "sHUqzb4cr1zB"
},
"source": [
"Постройте кривые обучения для различных `learning_rate`. Не обязательно рассматривать все `learning_rate`, так как их слишком много, и график будет нагроможден. Возьмите около половины из них."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Jj4MFLcRr5a2"
},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Какой `learning_rate` стоит выбирать в зависимости от способа обучения модели? Чем плохи маленькие и большие `learning_rate`?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"..."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "5ns_R7NEr7XA"
},
"source": [
"\n",
"\n",
"**4.** Рассмотрите наилучшую модель с предыдущего шага. Визуализируйте значения полученных коэффициентов."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "NCtU2t2Ur-zX"
},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Как можно проинтерпретировать полученные результаты относительно решаемой задачи?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"..."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "10PauxmiV3T5"
},
"source": [
"\n",
"\n",
"**5.** Сравните данную модель с бейзлайном, который в качестве предсказания выдает самый частый класс на обучающей выборке."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "25xDPq1GWTb3"
},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Насколько хорошее получилось качество обученной модели?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"..."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "R3nPAObnr_XI"
},
"source": [
"\n",
"\n",
"**6.** В исходной выборке оставьте два вещественных признака, которые имеют наибольшее влияние на предсказание в предыдущем пункте. Обучите на них модель на 10000 итерациях. Визуализируйте предсказание класса $1$ для нескольких промежуточных итераций."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "UGpyX1b-JMxW"
},
"outputs": [],
"source": [
"iters = [10, 20, 500, 1000, 5000, 10000]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "TNZAgIOGOSzW"
},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "GgV3-Y65sFQs"
},
"source": [
"\n",
"\n",
"**Вывод:**"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"..."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"\n",
"---\n",
"### Задача 6.\n",
"\n",
"В этой задаче вам предлагается реализовать регрессию Хьюбера, а также применить ее к данным с выбросами. Для начала реализуйте класс по шаблону снизу. Обратите внимание, что класс `HuberRegression` — наследник класса `BaseEstimator`, это с легкостью позволит использовать наш класс в различных пайплайнах библиотеки `sklearn`."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**1.** Задача оптимизации для регрессии Хьюбера выглядит следующим образом:\n",
"$$\\sum_{i=1}^n R\\left(Y_i - x_i^T\\theta\\right) \\rightarrow \\min_\\theta,$$\n",
"где $R(x)$ — функция потерь Хьюбера, определяемая как\n",
"$$R(x) = \\frac{x^2}{2} I\\left\\{|x| < c\\right\\} + c \\left(|x| - \\frac{c}{2}\\right)I\\left\\{|x| > c\\right\\}.$$\n",
"\n",
"Выпишите формулы для градиентного и стохастического градиентного спусков. В чем польза такой функции потерь?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"..."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"\n",
"**2.** Реализуем теперь класс. **При реализации класса запрещено пользоваться ИИ-инструментами.**"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# При реализации класса запрещено пользоваться ИИ-инструментами.\n",
"\n",
"\n",
"class HuberRegression(BaseEstimator):\n",
" \"\"\"Класс, реализующий линейную регрессию с функцией потерь Хьюбера.\"\"\"\n",
"\n",
" def __init__(self, c: float = 1.0, fit_intercept: bool = True, max_iter: int = 1000) -> None:\n",
" \"\"\"Инициализирует модель.\n",
"\n",
" Параметры: c (float): Константа из функции потерь Хьюбера.\n",
" fit_intercept (bool): Добавлять ли константный признак. max_iter\n",
" (int): Максимальное число итераций оптимизации.\n",
" \"\"\"\n",
" self.c = c\n",
" self.fit_intercept = fit_intercept\n",
" self.max_iter = max_iter\n",
"\n",
" def fit(self, X: np.ndarray, y: np.ndarray) -> \"HuberRegression\":\n",
" \"\"\"Обучает модель.\n",
"\n",
" Параметры:\n",
" X (np.ndarray): Матрица признаков.\n",
" y (np.ndarray): Вектор целевой переменной.\n",
"\n",
" Возвращает:\n",
" HuberRegression: Обученная модель.\n",
" \"\"\"\n",
" if X.shape[0] != y.shape[0]:\n",
" raise ValueError(\"Количество строк в X и y должно совпадать\")\n",
"\n",
" ...\n",
"\n",
" self.coef_ = ... # Коэффициенты модели\n",
" self.intercept_ = ... # Свободный коэффициент\n",
" self.n_iter_ = ... # Число итераций\n",
"\n",
" return self\n",
"\n",
" def predict(self, X: np.ndarray) -> np.ndarray:\n",
" \"\"\"Делает предсказание на новых данных.\n",
"\n",
" Параметры: X (np.ndarray): Матрица признаков.\n",
"\n",
" Возвращает: np.ndarray: Вектор предсказанных значений.\n",
" \"\"\"\n",
"\n",
" if X_copy.shape[1] != self.coef_.shape[0]:\n",
" raise ValueError(\"Число признаков в X не соответствует числу коэффициентов модели\")\n",
"\n",
" ...\n",
" return pred"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"\n",
"**3.** Загрузите данные из файлов `train.csv`, `test.csv`. Не забудьте, что всю аналитику, а также процесс обучения и подбор гиперпараметров необходимо выполнять на обучающей выборке."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"..."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Посмотрите на зависимость целевой переменной от каждого признака."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"..."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Что можно сказать о наличии возможных выбросов? Какое влияние они могут оказать? "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"..."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"\n",
"**4.** Обучите простую линейную регрессию и посчитайте качество на тестовой выборке по метрике [MSE](https://scikit-learn.org/stable/modules/generated/sklearn.metrics.mean_squared_error.html#sklearn.metrics.mean_squared_error)."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"..."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Что можно сказать о качестве нашей модели?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"..."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**5.** Теперь обучите линейную регресcию Хьюбера и посчитайте качество на тестовой части по метрикe MSE."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"..."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Что изменилось?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"..."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"\n",
"**6.** Для обучающей выборки постройте два графика (по графику на каждую модель), на которых изобразите зависимость истинного и предсказанного значения таргета от каждого признака."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"..."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Что можно заметить на этих графиках?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"..."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"\n",
"**7.** Обучите регрессию Хьюбера на данных из задачи 2 и сравните качество модели с простой линейной регрессией, которую вы построили в задаче 2."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"..."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Вывод:**"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"..."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"\n",
"---\n",
"### Задача 7.\n",
"\n",
"\n",
"Рассмотрим модель одномерной регрессии $y(x) = \\theta x$, где $x \\in \\mathbb{R}$ — одномерный признак, $y \\in \\mathbb{R}$ — целевой признак, $\\theta \\in \\mathbb{R}$ — неизвестный параметр. Имеется выборка размера $n$, полученная по правилу\n",
"\t$$Y_i = \\theta x_i + \\varepsilon_i,\\ \\ \\ i=1,...,n,$$\n",
"где $\\varepsilon_i$ — случайная ошибка измерений.\n",
"\n",
"Предложите точный алгоритм поиска оценки параметра $\\theta$ методом наименьших модулей, то есть $$\\sum_{i=1}^n \\left|Y_i - \\theta x_i\\right| \\to \\min_\\theta,$$ работающий за время $O(n \\log n)$. Приведите его описание и теоретическое обоснование. Реализация в коде не требуется."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Решение:**\n",
"\n",
"..."
]
}
],
"metadata": {
"colab": {
"provenance": [],
"toc_visible": true
},
"hide_input": false,
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"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.3"
}
},
"nbformat": 4,
"nbformat_minor": 1
}