Использование только NumPy

Что такое линейная регрессия? Почему это важно?

Линейная регрессия — это распространенный метод науки о данных и машинного обучения для прогнозирования числовых результатов на основе входных признаков.

Он является основополагающим и имеет множество реальных применений, от прогнозирования доходов от продаж до прогнозирования цен на жилье. Основная идея линейной регрессии заключается в том, чтобы сопоставить линию с набором точек данных, которые лучше всего отражают взаимосвязь между входными объектами и целевой переменной. Мы пытаемся найти линию, которая дает нам наименьшую ошибку между нашими прогнозируемыми и фактическими значениями. Это минимизирует функцию стоимости, обычно среднеквадратичную ошибку.

В этом сообщении блога вы реализуете линейную регрессию с нуля, используя библиотеку Python NumPy.

Мы рассмотрим все, от загрузки и подготовки данных до определения модели линейной регрессии, настройки функции стоимости и алгоритма градиентного спуска и оценки производительности модели. К концу этого поста вы будете иметь четкое представление о том, как работает линейная регрессия, и будете готовы применить ее к своим наборам данных.

Краткий обзор того, как работает линейная регрессия

Прежде чем перейти к коду, вам нужно понять, как работает линейная регрессия. В двух словах: линейная регрессия направлена ​​​​на поиск линии, которая лучше всего соответствует данным. Линия представлена ​​этим линейным уравнением:

y = mx + b

где:

y — целевая переменная (та, которую мы хотим предсказать).

x – входная функция.

m – наклон линии.

b – точка пересечения

В более обобщенном виде мы можем представить линейное уравнение следующим образом:

у = b0 + b1x1 + b2x2 + … + bnxn

Где:

• y по-прежнему является целевой переменной

• x1, x2, …, xn — входные объекты

• b0 – это член смещения (также известный как точка пересечения или константа).

• b1, b2, …, bn — это коэффициенты, которые мы хотим узнать

Цель линейной регрессии — найти значения для b0, b1, b2, …, bn, которые минимизируют разницу между прогнозируемыми значениями и фактическими значениями.

Представляя уравнение таким образом, вы теперь можете использовать матричную запись.

Вы можете сложить все входные признаки в матрицу X, где каждая строка представляет собой наблюдение, и добавить столбец единиц для смещения. Вы также можете сложить все целевые переменные в вектор y.

Уравнение тогда становится:

y = Xb

Где:

• y – вектор-столбец размером (m, 1) (где m – количество наблюдений)

X – матрица размера (m, n+1) (где n – количество входных признаков).

b – это вектор-столбец размера (n+1, 1) (который содержит член смещения и коэффициенты).

Эта матричная запись важна, потому что она позволяет легко выполнять линейную регрессию для нескольких входных функций.

В следующем разделе вы узнаете, как рассчитать функцию стоимости и использовать алгоритм градиентного спуска для оптимизации значений b.

Функция стоимости и градиентный спуск

Функция стоимости используется в линейной регрессии для измерения разницы между прогнозируемыми и фактическими значениями.

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

Формула МСЭ:

MSE = (1/m) * Σ(yi — yhat)²

Где:

• yhat – прогнозируемое значение для данного наблюдения.

yi – фактическое значение,

• m — общее количество наблюдений в наборе данных.

Цель линейной регрессии — минимизировать MSE, найдя значения коэффициентов, которые дают наименьшее возможное значение MSE.

Здесь в дело вступает градиентный спуск.

Градиентный спуск

Градиентный спуск — это итеративный алгоритм оптимизации, который минимизирует функцию стоимости в линейной регрессии.

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

Скорость обучения — это гиперпараметр, который определяет, насколько коэффициенты должны обновляться на каждой итерации.

Ключевыми параметрами градиентного спуска являются скорость обучения, количество итераций и условия остановки. Скорость обучения определяет размер шага алгоритма градиентного спуска. Небольшая скорость обучения может привести к медленной сходимости алгоритма. Напротив, большая скорость обучения может привести к тому, что алгоритм выйдет за пределы минимума и отклонится.

Важно выбрать подходящую скорость обучения, которая уравновешивает скорость сходимости и стабильность.

Количество итераций — это количество раз, когда алгоритм градиентного спуска будет обновлять коэффициенты. Дополнительные итерации могут привести к лучшему решению, но также могут увеличить риск переобучения обучающих данных. Условия остановки используются для определения момента остановки алгоритма градиентного спуска. Существуют различные условия остановки, такие как достижение определенного количества итераций, достижение минимального порога для функции стоимости или когда изменение функции стоимости между итерациями меньше определенного порога.

Рекомендуется комбинировать несколько условий остановки, чтобы гарантировать, что алгоритм градиентного спуска сходится к хорошему решению.

Реализация линейной регрессии

Теперь, когда мы рассмотрели теорию линейной регрессии и градиентного спуска, давайте рассмотрим, как реализовать линейную регрессию с помощью NumPy.

Шаг 1. Инициализация параметров модели
Первым шагом в реализации линейной регрессии является инициализация параметров модели. Это включает в себя настройку скорости обучения, количества итераций и начальных значений коэффициентов. Для простоты мы установим скорость обучения на 0,01 и количество итераций на 1000. Мы также инициализируем коэффициенты случайными значениями, используя случайный модуль NumPy.

Шаг 2. Подготовка данных
Следующим шагом является подготовка данных путем их загрузки в массивы NumPy и разделения на обучающие и тестовые наборы. Мы также добавим столбец единиц к обучающим данным, чтобы представить член смещения.

Шаг 3. Обучаем модель с помощью градиентного спуска
Теперь пришло время обучить модель с помощью градиентного спуска. Мы будем использовать цикл for для перебора количества итераций и обновления коэффициентов с помощью алгоритма градиентного спуска. На каждой итерации мы будем вычислять прогнозируемые значения для обучающих данных, используя текущие значения коэффициентов, а затем вычислять среднеквадратичную ошибку. Мы также будем печатать среднеквадратичное значение ошибки каждые 100 итераций.

Шаг 4. Делайте прогнозы на основе новых данных
После обучения модели мы можем использовать ее для прогнозирования новых данных. Мы сделаем это, рассчитав скалярное произведение тестовых данных и оптимизированных коэффициентов. Затем мы можем рассчитать среднеквадратичную ошибку для тестовых данных, чтобы оценить производительность модели.

Реализация линейной регрессии с использованием NumPy включает в себя настройку параметров модели, подготовку данных, обучение модели с использованием градиентного спуска и создание прогнозов на основе новых данных.

Следуя этим шагам, вы можете построить простую модель линейной регрессии, используя Python и NumPy.

Код

Далее определяется класс с именем Linear_Regression, который содержит несколько методов для выполнения линейной регрессии с использованием градиентного спуска.

Метод __init__ устанавливает значения по умолчанию для скорости обучения и количества итераций.

Метод initialize_betas принимает матрицу X и добавляет столбец единиц слева от X для учета члена смещения. Затем он инициализирует бета-версии случайными значениями и возвращает как X, так и betas.

Метод yhat принимает X и betas и возвращает предсказанные значения y путем умножения X на транспонирование betas.

Метод loss принимает предсказанные значения yhat и истинные значения y и вычисляет среднеквадратичную ошибку между ними.

Метод gradient_desc принимает текущие betas, X, y и yhat и вычисляет градиент функции потерь относительно betas. Затем он обновляет значения betas с помощью градиентного спуска и возвращает новые значения.

Метод main принимает X и y и инициализирует betas с помощью метода initialize_betas. Затем он запускает цикл iterations раз, в котором он вычисляет предсказанные значения y, используя yhat, вычисляет потери, используя loss, и обновляет betas, используя gradient_desc. Потеря печатается каждые 1000 итераций, а окончательная потеря печатается в конце. Метод возвращает окончательные значения betas.

Наконец, если скрипт запускается напрямую (то есть не импортируется), создается экземпляр класса Linear_Regression и вызывается метод main с X и y в качестве входных данных. Распечатываются окончательные значения betas.

import numpy as np
import random

class Linear_Regression:
    """
    A class for performing linear regression using gradient descent.
    """

    def __init__(self):
        """
        Constructor method that sets default values for the learning rate and number of iterations.
        """
        self.learning_rate = 0.001
        self.iterations = 10000
    
    def initialize_betas(self, X):
        """
        Method that takes in a matrix X and initializes the betas with random values, adding a column of ones to the left side of X to account for the bias term.
        
        Args:
            X: A matrix of shape (m, n) where m is the number of training examples and n is the number of features.
        
        Returns:
            X: A modified version of X with an additional column of ones to account for the bias term.
            betas: A numpy array of shape (1, n+1) containing the initial values for the betas.
        """
        ones = np.ones((X.shape[0], 1))
        X = np.append(ones, X, axis=1)
        
        self.m = X.shape[0]
        self.n = X.shape[1]
        
        betas = np.array([random.random() for i in range(self.n)]).reshape(1, self.n)
        return X, betas
    
    def yhat(self, X, betas):
        """
        Method that takes in X and betas and returns the predicted values of y.
        
        Args:
            X: A matrix of shape (m, n+1) where m is the number of training examples and n is the number of features (with an additional column of ones to account for the bias term).
            betas: A numpy array of shape (1, n+1) containing the values for the betas.
            
        Returns:
            yhat: A numpy array of shape (m, 1) containing the predicted values of y.
        """
        yhat = np.dot(X, betas.T)
        return yhat
    
    def loss(self, yhat, y):
        """
        Method that takes in the predicted values of y (yhat) and the true values of y and calculates the mean squared error between them.
        
        Args:
            yhat: A numpy array of shape (m, 1) containing the predicted values of y.
            y: A numpy array of shape (m, 1) containing the true values of y.
            
        Returns:
            loss: The mean squared error between y and yhat.
        """
        loss = np.sum(np.power((yhat - y), 2)) / self.m
        return loss
    
    def gradient_desc(self, betas, X, y, yhat):
        """
        Method that takes in the current values of betas, X, y, and yhat, calculates the gradient of the loss function with respect to betas, and updates the values of betas using gradient descent.
        
        Args:
            betas: A numpy array of shape (1, n+1) containing the current values of the betas.
            X: A matrix of shape (m, n+1) where m is the number of training examples and n is the number of features (with an additional column of ones to account for the bias term).
            y: A numpy array of shape (m, 1) containing the true values of y.
            yhat: A numpy array of shape (m, 1) containing the predicted values of y.
            
        Returns:
            betas: A numpy array of shape (1, n+1) containing the updated values of the betas.
        """
        dLdb = 2 * np.dot((yhat - y).T, X) / self.m
        betas = betas - self.learning_rate * dLdb
        return betas

def main(self, X, y):
    """
    Method that takes in X and y, initializes betas, and performs gradient descent to optimize the values of betas.
    
    Args:
        X: A matrix of shape (m, n) where m is the number of training examples and n is the number of features.
        y: A numpy array of shape (m, 1) containing the true values of y.
        
    Returns:
        betas: A numpy array of shape (1, n+1) containing the optimized values of the betas.
    """
    X, betas = self.initialize_betas(X)
    
    for iteration in range(self.iterations+1):
        yhat = self.yhat(X, betas)
        loss = self.loss(yhat, y)
        if iteration % 1000 == 0:
            print(loss)
        if iteration == self.iterations:
            print(f"Cost at iteration {iteration} is {loss}")
        betas = self.gradient_desc(betas, X, y, yhat)
    return betas

if name=="main":
"""
Main entry point of the script. Initializes an instance of the Linear_Regression class and calls the main method with a sample X and y.
"""
  X = np.array([[1, 2], [2, 4], [3, 6], [4, 8], [5, 10]])
  y = np.array([[2], [4], [6], [8], [10]])
  regression = Linear_Regression()
  w = regression.main(X, y)
  print(w)

Подведение итогов кода

Этот код определяет класс Linear_Regression с различными методами для выполнения линейной регрессии с использованием градиентного спуска.

  • Класс может быть импортирован и создан, а его метод main вызывается с входными данными X и Y.
  • Метод «__init__» инициализирует две переменные, «learning_rate» и «iterations», равными 0,01 и 10000 соответственно.
  • Метод «initialize_betas» принимает «X», добавляет столбец единиц слева от «X», чтобы учесть член смещения, и инициализирует «беты» случайными значениями. Он возвращает измененные «X» и «беты».
  • Метод «yhat» принимает «X» и «бета». Он возвращает предсказанные значения «y» путем умножения «X» на транспонирование «бета».
  • Метод «потери» принимает значения «yhat» и «y» и вычисляет среднеквадратичную ошибку между ними.
  • Метод «gradient_desc» принимает текущие значения «бета», «Х», «у» и «yhat», вычисляет градиент функции потерь для «бета» и обновляет значения «бета», используя градиент спуск.
  • Метод «main» принимает «X» и «y», инициализирует «беты» с помощью «initialize_betas» и выполняет градиентный спуск для оптимизации значений «бета». Он повторяет «итерации» много раз, обновляя значение « betas` каждый раз, используя метод `gradient_desc`, и печатает потери каждые 1000 итераций. Он возвращает оптимизированные значения «бета».
  • Сценарий можно запустить напрямую, чтобы протестировать класс с образцом `X` и `y`. Он создает экземпляр объекта Linear_Regression, вызывает метод main с образцом.

Оценка и интерпретация

После того, как вы обучили модель линейной регрессии и сделали прогнозы на основе новых данных, вы должны оценить производительность модели.

Вы можете использовать несколько показателей, включая R-квадрат и среднюю абсолютную ошибку (MAE).

R-квадрат, также известный как коэффициент детерминации, представляет собой статистическую меру, которая представляет долю дисперсии зависимой переменной, объясняемую независимыми переменными модели. Он находится в диапазоне от 0 до 1, причем более высокие значения указывают на лучшее соответствие.

Для расчета R-квадрата мы можем использовать следующую формулу:

R-квадрат = 1 — (SSres / SStot)

SSres – это сумма квадратов остатков (разницы между прогнозируемыми и фактическими значениями). Sstot – это общая сумма квадратов (разница между фактическими значениями и средним значением зависимой переменной).

MAE – это показатель, представляющий среднюю абсолютную разницу между прогнозируемыми и фактическими значениями.

Он рассчитывается как:

МАЭ = (1/n) * Σ|yi — yhat|

Где yi — фактическое значение для данного наблюдения, yhat — прогнозируемое значение, а n — количество наблюдений.

Интерпретация коэффициентов модели также является важной частью оценки модели. Коэффициенты представляют силу и направление связи между независимыми и зависимыми переменными. Положительный коэффициент указывает на положительную связь, а отрицательный коэффициент указывает на отрицательную связь. Величина коэффициента указывает на силу связи, причем большие значения указывают на более сильную связь.

Помните, что коэффициенты имеют смысл только в контексте входных данных.

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

Оценка производительности модели линейной регрессии включает в себя расчет таких показателей, как R-квадрат и MAE, и интерпретацию коэффициентов, чтобы получить представление о взаимосвязи между входными функциями и целевой переменной.

Заключение

Хорошо, вы дошли до конца!

Вот краткое изложение того, что вы узнали из этого сообщения в блоге:

  • Линейная регрессия — это основополагающий метод в науке о данных и машинном обучении, используемый для прогнозирования числовых результатов на основе входных признаков.
  • Цель линейной регрессии — найти линию, которая лучше всего соответствует данным, путем минимизации функции стоимости, которая обычно представляет собой среднеквадратичную ошибку.
  • Градиентный спуск — это итеративный алгоритм оптимизации, который минимизирует функцию стоимости в линейной регрессии.
  • Чтобы реализовать линейную регрессию с помощью NumPy, вам необходимо инициализировать параметры модели, подготовить данные, обучить модель с помощью градиентного спуска и оценить производительность с использованием таких показателей, как R-квадрат и средняя абсолютная ошибка.

Теперь, когда вы понимаете, как работает линейная регрессия и как ее реализовать с помощью NumPy, что дальше? Небо это предел!

Вот некоторые возможные следующие шаги для применения линейной регрессии к реальным проблемам:

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

Спасибо за чтение и удачи в вашем путешествии по линейной регрессии!