Представление и реализация модели линейной регрессии с нуля в Python

Введение

Цель этой записной книжки — реализовать линейную регрессию с нуля, используя математическое представление модели с помощью Python. во-первых, решение простой линейной регрессии с одной переменной, затем решение модели множественной линейной регрессии для прогнозирования жилья и сравнение результатов с классами предварительной сборки sklearn и, наконец, использование более сложного набора данных: Цены на жилье — передовые методы регрессии для прогнозирования цен продаж.

Весь процесс будет задокументирован в Jupiter Nootebook.

Линейная регрессия

Линейная регрессия — это статистический метод, используемый для моделирования линейной зависимости между зависимой переменной, обозначенной как Y, и одной или несколькими независимыми переменными, обозначенными как X. [1]

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

Уравнение для простой модели линейной регрессии с одной переменной-предиктором:

Y = b0 + b1 * X

Где b0 — член перехвата, а b1 — коэффициент для переменной-предиктора X.

В модели множественной линейной регрессии с несколькими переменными-предикторами уравнение можно записать как:

Y = b0 + b1 * X1 + b2 * X2 + … + bn * Xn

где X1, X2, …, Xn — переменные-предикторы, а b1, b2, …, bn — соответствующие коэффициенты.

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

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

Вдохновение:

Формулировка модели, содержание и реализация основаны на программе Специализация машинного обучения, созданной в сотрудничестве между DeepLearning.AI и Stanford Online, которая научит вас основам машинного обучения. обучение и как создавать модели машинного обучения на Python, используя популярные библиотеки машинного обучения с NumPy

Также я использую ChatGPT для описания некоторых концепций: например, объяснить простую линейную регрессию с одной переменной.

Простая линейная регрессия с одной переменной

Линейная регрессия с одной переменной — это статистический метод, используемый для моделирования связи между одной независимой переменной (x) и зависимой переменной (y). Предполагается, что связь между двумя переменными является линейной, что означает, что y является линейной функцией x. Цель линейной регрессии — найти наиболее подходящую линию через точки данных, которую можно использовать для прогнозирования значения y для любого заданного значения x. Наилучшая линия определяется путем нахождения значений наклона и точки пересечения y, которые минимизируют сумму квадратов разностей между предсказанным и фактическим значениями y. Этот метод также известен как простая линейная регрессия [1].

Набор данных

Файл dataset1.txt содержит набор данных для нашей задачи линейной регрессии. Первый столбец — это население города, а второй столбец — прибыль фудтрака в этом городе. [3]

Примечание. Набор данных не требует предварительной обработки

Обозначение:

m = количество обучающих примеров.

X = «Входные» переменные/функции

y = "Выходная" переменная / "целевая" переменная

Набор данных загружается из файла данных в переменные X и y:

#Read the text file (csv)
df = pd.read_csv('https://raw.githubusercontent.com/DiegoHurtad0/Linear-Regression-Model-Representation-Implementation-From-Scratch-using-Python/main/data/dataset1.txt', skiprows = 0, header = None, names = ['population', 'profit'])
#Form the usual "X" matrix and "y" vector
X = df[['population']]['population'].values
y = df[['profit']].values

m = y.size #number of training examples

#Reshape y to a mx1 matrix
y = y.reshape((m, 1))

df.head(3)

График данных

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

Градиентный спуск — это алгоритм оптимизации, используемый для минимизации функции. Он работает путем итеративного движения в направлении наискорейшего спуска, определяемого отрицательным значением градиента. [4]

С математической точки зрения предположим, что у нас есть функция f(x), которую мы хотим минимизировать, где x — вектор параметров. Градиент функции по параметрам представляет собой вектор частных производных функции по каждому параметру

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

где η — скорость обучения, которая определяет размер шага на каждой итерации.

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

Мы используем Gradient Decent, чтобы подогнать параметры линейной регрессии θ к нашему набору данных.

Обновление уравнений

Цель линейной регрессии состоит в том, чтобы минимизировать функцию стоимости

где гипотеза hθ(x) задается линейной моделью:

Напомним, что параметры вашей модели — это значения θj. Это значения, которые вы будете корректировать, чтобы минимизировать стоимость J(θ). Один из способов сделать это — использовать алгоритм пакетного градиентного спуска. В пакетном градиентном спуске каждая итерация выполняет обновление

С каждым шагом градиентного спуска ваши параметры θj приближаются к оптимальным значениям, которые позволят достичь наименьшей стоимости J(θ).

Выполнение

Мы уже настроили данные для линейной регрессии. В следующей ячейке мы добавляем еще одно измерение к нашим данным, чтобы учесть термин пересечения θ0.

# Add a column of ones to X. The numpy function stack joins arrays along a given axis. 
# The first axis (axis=0) refers to rows (training examples) 
# and second axis (axis=1) refers to columns (features).
X = np.stack([np.ones(m), X], axis=1)

Вычисление стоимости 𝐽(𝜃)

Когда вы выполняете градиентный спуск, чтобы научиться минимизировать функцию стоимости 𝐽(𝜃)J(θ), полезно отслеживать сходимость, вычисляя стоимость.

В этом разделе вы реализуете функцию для вычисления 𝐽(𝜃), чтобы вы могли проверить сходимость вашей реализации градиентного спуска.

Функция computeCost, которая вычисляет 𝐽(𝜃). При этом помните, что переменные 𝑋 и 𝑦 являются не скалярными значениями, а матрицами, строки которых представляют примеры из обучающей выборки.

Вычисляет стоимость использования тета в качестве параметра для линейной регрессии, чтобы соответствовать точкам данных в X и y

Вычислите стоимость конкретного выбора тэты. Вы должны установить J на ​​стоимость.

def computeCost(X, y, theta):
    m = y.size  # number of training examples
    # You need to return the following variables correctly
    J = 0.0
    J = 1./(2. * m) * np.sum((np.dot(X, theta) - y)**2)
    return J

Метод градиентного спуска

Далее вы реализуете градиентный спуск в функции. Структура цикла была написана для вас, и вам нужно только предоставлять обновления для 𝜃θ в каждой итерации.

Когда вы программируете, убедитесь, что вы понимаете, что вы пытаетесь оптимизировать и что обновляется. Имейте в виду, что стоимость 𝐽(𝜃) параметризуется вектором 𝜃, а не 𝑋 и 𝑦y. То есть мы минимизируем значение 𝐽(𝜃), изменяя значения вектора 𝜃, а не меняя 𝑋 или 𝑦. Обратитесь к уравнениям в этой тетради и к слайдам лекции, если вы не уверены. Хороший способ убедиться, что градиентный спуск работает правильно, — посмотреть на значение 𝐽(𝜃) и убедиться, что оно уменьшается с каждым шагом.

Стартовый код для функции gradientDescent вызывает computeCost на каждой итерации и сохраняет стоимость в списке python. Предполагая, что вы реализовали градиентный спуск и computeCost правильно, ваше значение 𝐽(𝜃)J(θ) никогда не должно увеличиваться и должно сходиться к устойчивому значению к концу алгоритма.

def gradientDescent(X, y, theta, alpha, num_iters):
    # Initialize some useful values
    m = y.shape[0]  # number of training examples
    # are passed by reference to functions
    theta = theta.copy()
    J_history = [] # Use a python list to save cost in every iteration
    
    for i in range(num_iters):
        theta = theta - (alpha/m) * np.dot(X.T, (np.dot(X, theta) - y))
        # save the cost J in every iteration
        J_history.append(computeCost(X, y, theta))
    
    return theta, J_history

После того, как вы закончите, вызовите реализованную функцию gradientDescent и распечатайте вычисленное 𝜃θ. Мы инициализируем параметры θ равными 0, а скорость обучения 𝛼α — 0,01. Выполните следующую ячейку, чтобы проверить свой код.

# initialize fitting parameters
theta = np.zeros((2, 1))
# some gradient descent settings
iterations = 1500
alpha = 0.01

# run gradient descent
theta, J_hist = gradientDescent(X, y, theta, alpha, iterations)

print('Theta found by gradient descent:')
print('𝜃 = ' + str(theta[0][0])  + ' , ' + str(theta[1][0]) )

Тета найдена градиентным спуском:
𝜃 = -3,6302914394043593, 1,1663623503355818

Визуализация линейной подгонки

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

Прогноз прибыли для фудтрака

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

prediction_Value = 7 (население в 10 000 с)

Предсказания алгоритма линейной регрессии с нуля

predict = np.dot([[1, prediction_Value]], theta)
print('The 𝜃 value: ' + str(theta[0][0])  + ' , ' + str(theta[1][0]) )
print('For population = 70,000, we predict a profit of $', round(predict[0][0]*10000, 2))

Значение 𝜃: -3,6302914394043593, 1,1663623503355818
Для населения = 70 000 мы прогнозируем прибыль в размере45342,45 долл. США.

Прогнозы модели линейной регрессии от sklearn

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

from sklearn.linear_model import LinearRegression

X = df[['population']]
y = df[['profit']]

reg = LinearRegression().fit(X, y)
print('Score:')
print(reg.score(X, y))

print('The 𝜃 value: ' + str(reg.intercept_[0]) + ' , ' + str(reg.coef_[0][0]))
print('For population = 70,000, we predict a profit of $', round(reg.predict(np.array([[7]]))[0][0] * 10000, 2))

Оценка:
0,7020315537841397
Значение 𝜃: -3,89578087831185, 1,1930336441895935
Для населения = 70 000 мы прогнозируем прибыль 44554,55 долл. США

Визуализация 𝐽(𝜃)

Чтобы лучше понять функцию стоимости 𝐽(𝜃), вы теперь нанесете стоимость на двумерную сетку значений 𝜃0 и 𝜃1. Вам не нужно будет кодировать что-то новое для этой части, но вы должны понимать, как код, который вы уже написали, создает эти изображения.

В следующей ячейке код настроен для вычисления 𝐽(𝜃) по сетке значений с использованием написанной вами функции computeCost. После выполнения следующей ячейки у вас будет двумерный массив значений 𝐽(𝜃). Затем эти значения используются для создания поверхностных и контурных графиков 𝐽(𝜃) с использованием функций matplotlib plot_surface и contourf. Графики должны выглядеть примерно так:

Цель этих графиков — показать вам, как 𝐽(𝜃) меняется при изменении 𝜃0 и 𝜃1. Функция стоимости 𝐽(𝜃) имеет форму чаши и имеет глобальный минимум. (Это легче увидеть на контурном графике, чем на трехмерном графике поверхности). Этот минимум является оптимальной точкой для 𝜃 и 𝜃1, и каждый шаг градиентного спуска приближается к этой точке.

Линейная регрессия с несколькими переменными

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

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

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

Набор данных

Файл dataset2.txt содержит обучающий набор цен на жилье в Портленде, штат Орегон. Первый столбец — это размер дома (в квадратных футах), второй столбец — количество спален, а третий столбец — цена дома. [3]

Примечание. Набор данных не требует предварительной обработки

Обозначение:

m = количество обучающих примеров.

X = «Входные» переменные/функции

y = "Выходная" переменная / "целевая" переменная

#Load Data
df = pd.read_csv('https://raw.githubusercontent.com/DiegoHurtad0/Linear-Regression-Model-Representation-Implementation-From-Scratch-using-Python/main/data/dataset2.txt', skiprows = 0, header = None, names = ['size sq-ft', 'bedrooms', 'price'])
X = df[['size sq-ft', 'bedrooms']].values
y = df[['price']].values
m = y.size
#Reshape y to a mx1 matrix
y = y.reshape((m, 1))

df.head(5)

Нормализация функций

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

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

Например, предположим, что у нас есть набор данных с числовым столбцом x. Чтобы нормализовать эту функцию, мы можем применить следующее преобразование к каждому значению xi в столбце:

xi_normalized = (xi — среднее (x)) / стандартное (x)

где среднее (x) и стандартное отклонение (x) — среднее значение и стандартное отклонение признака x соответственно.

Другой метод нормализации признаков — масштабирование значений до фиксированного диапазона, например [0, 1] или [-1, 1]. Это можно сделать, вычитая минимальное значение признака из каждого значения, а затем разделив результат на диапазон (максимум — минимум) признака.

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

Этот метод используется во многих библиотеках машинного обучения, таких как scikit-learn, TensorFlow и Keras.

Источник: документация scikit-learn (https://scikit-learn.org/stable/modules/preprocessing.html#preprocessing-scaler)

Нормализация функций с нуля

def  featureNormalize(X):
    X_norm = X.copy()
    mu = np.zeros(X.shape[1])
    sigma = np.zeros(X.shape[1])
    mu = np.mean(X, axis = 0)
    sigma = np.std(X, axis = 0)
    
    X_norm = X_norm - mu
    X_norm = X_norm / sigma
    return X_norm, mu, sigma
# call featureNormalize on the loaded data
X_norm, mu, sigma = featureNormalize(X)

Вычисленное среднее: [2000,68085106 3,17021277]
Вычисленное стандартное отклонение: [7,86202619e+02 7,52842809e-01]

Нормализация функций из класса StandardScaler

Источник: документация scikit-learn (https://scikit-learn.org/stable/modules/preprocessing.html#preprocessing-scaler)

from sklearn import preprocessing
scaler = preprocessing.StandardScaler().fit(X)
# call featureNormalize on the loaded data
X_scaled = scaler.transform(X)

Вычисленное среднее: [2000,68085106 3,17021277]
Вычисленное стандартное отклонение: [7,86202619e+02 7,52842809e-01]

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

Ранее вы реализовали градиентный спуск для задачи одномерной регрессии. Единственное отличие теперь в том, что в матрице 𝑋 появился еще один признак. Функция гипотезы и правило обновления пакетного градиентного спуска остаются без изменений. [3]

Вы должны завершить код для функций computeCostMulti и gradientDescentMulti, чтобы реализовать функцию стоимости и градиентный спуск для линейной регрессии с несколькими переменными. Если ваш код в предыдущей части (одна переменная) уже поддерживает несколько переменных, вы можете использовать его и здесь. Убедитесь, что ваш код поддерживает любое количество функций и хорошо векторизован. Вы можете использовать свойство shape массивов numpy, чтобы узнать, сколько функций присутствует в наборе данных.

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

def computeCostMulti(X, y, theta):
    m = y.shape[0] # number of training examples
    J = 0.0
    J = 1./(2. * m) * np.sum((np.dot(X, theta) - y)**2)
    return J

Где

def gradientDescentMulti(X, y, theta, alpha, num_iters):
    m = y.shape[0] # number of training examples
    
    # make a copy of theta, which will be updated by gradient descent
    theta = theta.copy()
    
    J_history = []
    
    for i in range(num_iters):
        theta = theta - (alpha/m) * np.dot(X.T, (np.dot(X, theta) - y))
        # save the cost J in every iteration
        J_history.append(computeCostMulti(X, y, theta))
    
    return theta, J_history

Выбор ставок обучения

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

Используйте свою реализацию функции gradientDescentMulti и запустите градиентный спуск примерно на 50 итераций с выбранной скоростью обучения. Функция также должна возвращать историю значений 𝐽(𝜃)J(θ) в векторе 𝐽J.

После последней итерации нарисуйте значения J в зависимости от количества итераций.

Предсказать цену дома

Теперь, когда мы реализуем модель, мы можем начать делать некоторые прогнозы.

Метрики оценки регрессии

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

Существует несколько общих показателей регрессионной оценки, в том числе:

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

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

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

R-квадрат (R2). Этот показатель является мерой качества соответствия модели. Он находится в диапазоне от 0 до 1, причем более высокие значения указывают на лучшее соответствие.

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

Значения:

size_ft = 1650 # sq-ft
ванные комнаты = 3

Предсказать цену дома, используя нашу модель

тета, вычисленная методом градиентного спуска:[[340412,56301439 [109370,05670466] [-6500,61509507]]

Прогнозируемая цена дома площадью 1650 кв. футов с 3 спальнями: 293098,5

Прогнозирование цены дома с использованием модели линейной регрессии из sklearn.linear_model

X = X_scaled
y = df[['price']]

reg = LinearRegression().fit(X, y)
print('The accuracy of the Linear Regression model:')
print(reg.score(X, y))

print('The 𝜃 value: ' + str(reg.intercept_[0]) + ' , ' + str(reg.coef_[0][0]))
print('Predicted price of a 1650 sq-ft, 3 br house (sklearn.linear_model):', round(reg.predict(np.array([[(size_ft - mu[0])/sigma[0], (bathrooms - mu[1]) / sigma[1]]]))[0][0], 1) )

Точность модели линейной регрессии:
0,7329450180289143
Значение 𝜃:340412,6595744681 , 109447,7964696418
Прогнозируемая цена 1650 кв. футов , 3-х комн. дом (sklearn.linear_model): 293081.5

Мы можем заметить, что прогноз не такой уж «хороший»: 0,73.

Недооснащение

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

  1. Модель слишком проста. Если в модели всего несколько параметров, она может не отразить всю сложность данных. В таких случаях может потребоваться более сложная модель с большим количеством параметров.
  2. Данные нелинейны. Если данные имеют нелинейную зависимость между независимыми и зависимыми переменными, линейная модель не сможет хорошо соответствовать данным.
  3. Недостаточно данных. При наличии ограниченных данных модель может быть не в состоянии изучить базовую взаимосвязь между независимыми и зависимыми переменными.

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

Как решить Underfitting в модели линейной регрессии

Есть несколько способов решить проблему недообучения в линейной регрессии:

  1. Добавление дополнительных функций. При добавлении дополнительных функций модель может стать более сложной, что позволит более точно отражать базовую взаимосвязь между независимыми и зависимыми переменными.
  2. Использование нелинейных функций. Добавление нелинейных функций или взаимодействий между функциями может помочь модели зафиксировать нелинейные отношения в данных.
  3. Использование более сложной модели.Вместо использования линейной модели использование более сложной модели, такой как полиномиальная регрессия, регрессия дерева решений или регрессия случайного леса, может лучше соответствовать данным.
  4. Увеличение объема данных. При наличии большего количества данных модель может более точно изучить лежащую в основе взаимосвязь между независимыми и зависимыми переменными.
  5. Регуляризация. Регулировка — это метод, который помогает предотвратить переобучение путем добавления штрафного члена к функции потерь, чтобы не допустить больших коэффициентов. Регуляризация L1 и L2 — наиболее популярные способы регуляризации линейной регрессии.
  6. Перекрестная проверка.Использование методов перекрестной проверки (например, перекрестная проверка в k-кратном порядке) может помочь выявить и избежать переобучения путем оценки производительности модели на невидимых данных.

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

В этом случае мы можем заметить, что у нас есть только 2 функции, а размер выборки данных невелик (47).

Настройка поезда и тестового разделения

Настройка разделения обучения и тестирования — это распространенный метод, используемый в машинном обучении для оценки производительности модели. Цель разделения обучения и тестирования — оценить способность модели обобщать новые, невидимые данные.

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

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

Таким образом, настройка разделения обучения и тестирования — важный шаг в процессе машинного обучения, поскольку он помогает оценить способность модели обобщать новые, невидимые данные и убедиться, что она не является переоснащением или недообучением.

from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=2)

Линейная регрессия с разделенным набором данных

from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score

#Create linear regression 
reg = LinearRegression()

#Train the model using the training sets
reg.fit(X_train, y_train)

# Make predictions using the testing set
y_pred = reg.predict(X_test)
print('The accuracy of the Linear Regression',r2_score(y_test,y_pred))
print('The 𝜃 value: ' + str(reg.intercept_[0]) + ' , ' + str(reg.coef_[0][0]))
print('Predicted price of a 1650 sq-ft, 3 br house (linear_model.LinearRegression):', round(reg.predict(np.array([[(size_ft - mu[0])/sigma[0], (bathrooms - mu[1]) / sigma[1]]]))[0][0], 1) )
print ('RMSE: ', mean_squared_error(y_test, y_pred))

Точность линейной регрессии 0,8268330726601523
Значение 𝜃: 341272,94128357305 , 108050,93183004484
Прогнозируемая цена дома с 3 спальнями, площадью 1650 кв. футов (linear_model.LinearRegression): 292732. 0
СКО: 2226159168.988815

Регуляризация

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

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

Лассо-регрессия (регуляризация L1)

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

from sklearn.linear_model import Lasso

lasso=Lasso(alpha=0.8)
lasso.fit(X_train, y_train)
y_pred3=lasso.predict(X_test)

print('The accuracy of the Lasso Regression',lasso.score(X_test, y_test))
print('Predicted price of a 1650 sq-ft, 3 br house (linear_model.Lasso):', round(lasso.predict(np.array([[(size_ft - mu[0])/sigma[0], (bathrooms - mu[1]) / sigma[1]]]))[0], 2) )

Ридж-регрессия (регуляризация L2)

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

from sklearn.linear_model import Ridge

#Create Ridge regression 
ridge = Ridge()

#Train the model using the training sets
ridge.fit(X_train, y_train)
b = float(ridge.intercept_)

# Make predictions using the testing set - Ridge Regression
test_ridge = ridge.predict(X_test)
print('The accuracy of the Ridge Regression is', r2_score(y_test, test_ridge))
print('Predicted price of a 1650 sq-ft, 3 br house (linear_model.Lasso):', round( ridge.predict(np.array([[(size_ft - mu[0])/sigma[0], (bathrooms - mu[1]) / sigma[1]]]))[0][0] , 2) )

Настройка гиперпараметров

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

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

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

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

Настройка гиперпараметров Ридж-регрессия (регуляризация L2)

#find best alpha for Ridge Regression
from sklearn.model_selection import GridSearchCV

param_grid={'alpha':np.arange(1,10,500)} #range from 1-500 with equal interval of 10 
ridge=Ridge() 
ridge_best_alpha=GridSearchCV(ridge, param_grid)
ridge_best_alpha.fit(X_train,y_train)

print("Best alpha for Ridge Regression:",ridge_best_alpha.best_params_)
print("Best score for Ridge Regression with best alpha:",ridge_best_alpha.best_score_)

Настройка гиперпараметров Лассо-регрессия (регуляризация L1)

from sklearn.model_selection import GridSearchCV

param_grid={'alpha':np.arange(0,0.1,1)} #range from 0-1 with equal interval of 0.1 
lasso=Lasso() 
lasso_best_alpha=GridSearchCV(lasso, param_grid) 
lasso_best_alpha.fit(X_train,y_train)

print("Best alpha for Lasso Regression:",lasso_best_alpha.best_params_)
print("Best score for Lasso Regression with best alpha:",lasso_best_alpha.best_score_)

Лучший результат для регрессии Лассо с лучшей альфой: 0,15732202460557382

#seting alpha as 20
alpha = lasso_best_alpha.best_score_ 

# Initialising Lasso() with above alpha
lasso = Lasso(alpha=alpha)

#fitting model
lasso.fit(X_train,y_train)

print('The accuracy of the Lasso Regression',lasso.score(X_test, y_test))
print('Predicted price of a 1650 sq-ft, 3 br house (linear_model.Lasso):', round(lasso.predict(np.array([[(size_ft - mu[0])/sigma[0], (bathrooms - mu[1]) / sigma[1]]]))[0], 2) )

Точность регрессии Лассо 0,826833643868359
Прогнозируемая цена дома с 3 спальнями площадью 1650 кв. футов (linear_model.Lasso): 292732,05

Настройка гиперпараметров ElasticNet Regression

from sklearn.linear_model import ElasticNet

# list of alpha to tune
params = {'alpha': [0.0001, 0.001, 0.01, 0.05, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]}

# defining cross validation folds as 8
folds = 8

# Initialising ElasticNet()
elasticnet = ElasticNet() 

#using same attributes used for Ridge tuning except estimator here would be ElasticNet
grid_cv_model = GridSearchCV(
                       estimator=elasticnet,
                       param_grid=params,
                       scoring='neg_mean_absolute_error',
                       cv=folds,
                       return_train_score=True,
                       verbose=1
)

#fitingmodel_cv
grid_cv_model.fit(X_train,y_train)

# Checking best  alpha from model_cv
print(grid_cv_model.best_params_)

alpha = grid_cv_model.best_params_["alpha"]

# Defining ElasticNet with above alpha
elasticnet = ElasticNet(alpha=alpha)
  
# fiting elastic net
elasticnet.fit(X_train,y_train)

pred_by_elasticnet = elasticnet.predict(X_test)

print('The accuracy of the Ridge Regression is', round(r2_score(y_test, pred_by_elasticnet), 2))
print(f'ElasticNet RMSE: {np.sqrt(mse(y_test,pred_by_elasticnet))}')
print('Predicted price of a 1650 sq-ft, 3 br house (linear_model.Lasso):', round(elasticnet.predict(np.array([[(size_ft - mu[0])/sigma[0], (bathrooms - mu[1]) / sigma[1]]]))[0], 2) )

Прогнозная цена дома 1650 кв.м с 3 спальнями (linear_model.Lasso): 295701,11

Следующим этапом является применение этих концепций к более сложному набору данных.

Для этого я использую набор данных о соревнованиях [House Prices — Advanced Regression Techniques](https://www.kaggle.com/competitions/house-prices-advanced-regression-techniques/overview/description) [6].

Перед началом моделирования нам нужно проверить набор данных

ЭДА

Исследовательский анализ данных (EDA) — это подход к анализу и обобщению наборов данных для получения информации и понимания данных. Это важный шаг в процессе обработки данных, поскольку он помогает выявить закономерности, тенденции и взаимосвязи в данных, которые могут информировать более поздние этапы процесса, такие как построение моделей или принятие решений. EDA обычно включает визуализацию данных с использованием графиков и графиков, а также применение статистических методов для обобщения и понимания данных. Он называется «исследовательским», потому что аналитик часто не уверен в том, что он ищет в данных, и использует EDA, чтобы помочь ему узнать, что данные могут ему сказать.

У нас 1460 строк и 81 столбец.

Нормализация, удаление выбросов и асимметрии

Заполнение пропущенных значений

from sklearn.base import TransformerMixin
from sklearn.base import BaseEstimator

class DataImputer(BaseEstimator, TransformerMixin):
    def __init__(self, strategy, filler):
        self.strategy = strategy
        self.fill = filler
        """
        Impute missing values.

        """
    def fit(self, X, column, strategy):
        if strategy == 'mean':
            X[column] = X[column].mean()
        elif strategy == 'median':
            X[column] = X[column].median()
        elif strategy == 'mode':
            X[column] = X[column].mode().iloc[0]
        elif strategy == 'zero':
            X[column] = X[column].fillna(0)
        elif strategy == 'none':
            X[column] = df[column].fillna("None")
                
        return X[column]

Заполнение отсутствующих значений

imputer = DataImputer(BaseEstimator, TransformerMixin)

df_clean = pd.read_csv('https://raw.githubusercontent.com/DiegoHurtad0/Linear-Regression-Model-Representation-Implementation-From-Scratch-using-Python/main/data/data_cleaning_hp.csv')

df["LotFrontage"] = df.groupby("Neighborhood")["LotFrontage"].transform(
    lambda x: x.fillna(x.median()))

## loop to filling the missing Values using the DataInputer Class
for i in df_clean['fill type'].unique():
    strategy = i
    for j in df_clean[df_clean['fill type'] == i]['column name'].tolist():
        column = j
        print(strategy  + column)
        df[column] = imputer.fit(df, column, strategy)

В этой версии я использую те же переменные, что и в предыдущем упражнении.

X = df[['Totalsqr', 'BedroomAbvGr']].values
y = df[['SalePrice']].values
m = y.size
#Reshape y to a mx1 matrix
y = y.reshape((m, 1))

df.head(5)

Масштабирование функций

from sklearn import preprocessing

scaler = preprocessing.StandardScaler().fit(X)

# call featureNormalize on the loaded data
X_norm, mu, sigma = featureNormalize(X)

print('Computed mean:', mu)
print('Computed standard deviation:', sigma)

# call featureNormalize on the loaded data
X_scaled = scaler.transform(X)
print('Computed mean:', scaler.mean_)
print('Computed standard deviation:', sigma)

X = X_scaled

Обучайте и тестируйте наборы данных

from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=2)

Линейная регрессия

from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=2)

size_ft = 2416 # sq-ft
bathrooms = 3

from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score

#Create linear regression 
reg = LinearRegression()

#Train the model using the training sets
reg.fit(X_train, y_train)

# Make predictions using the testing set
y_pred = reg.predict(X_test)
print('The accuracy of the Linear Regression',r2_score(y_test,y_pred))
print('The 𝜃 value: ' + str(reg.intercept_[0]) + ' , ' + str(reg.coef_[0][0]))
print('Predicted price of a ' + str(size_ft) + ' sq-ft, 3 br house (linear_model.LinearRegression):', round(reg.predict(np.array([[(size_ft - mu[0])/sigma[0], (bathrooms - mu[1]) / sigma[1]]]))[0][0], 1) )
print ('RMSE: ', mean_squared_error(y_test, y_pred))

Регрессия хребта

from sklearn.linear_model import Ridge

#Create Ridge regression 
ridge = Ridge()

#Train the model using the training sets
ridge.fit(X_train, y_train)
b = float(ridge.intercept_)

# Make predictions using the testing set - Ridge Regression
test_ridge = ridge.predict(X_test)
print('The accuracy of the Ridge Regression is', r2_score(y_test, test_ridge))
print('Predicted price of a ' + str(size_ft) + ' sq-ft, 3 br house (linear_model.Lasso):', round( ridge.predict(np.array([[(size_ft - mu[0])/sigma[0], (bathrooms - mu[1]) / sigma[1]]]))[0][0] , 2) )

Прогнозы:

Фактическая цена продажи: 12 247 долларов США.

Линейная регрессия: 12,3

Лассо-регрессия: 12,28

Выводы:

Цель этого поста — объяснить модельное представление линейной регрессии и реализацию с нуля, чтобы понять, что стоит за классами предварительной сборки моделей, и сравнить реализацию с классами предварительной сборки sklearn.

Будущая работа:

Расскажите подробнее о процессе предварительной обработки

Используйте все столбцы

Разработка функций, выбор функций

Используйте более сложные методы, такие как:

  • XGBoost регрессор
  • Объяснить Подробнее о процессе обработки данных
  • Регрессор повышения градиента света
  • Регрессор опорных векторов
  • Регрессор повышения градиента
  • Случайный лесной регрессор

Юпитер Ноотебок:

https://github.com/DiegoHurtad0/Linear-Regression-Model-Representation-Implementation-From-Scratch-using-Python

Свяжитесь со мной:

Linkedin:Диего Густаво Уртадо Оливарес

Рекомендации

[1] «Введение в линейный регрессионный анализ» Дугласа К. Монтгомери, Элизабет А. Пек, Г. Джеффри Вининга. опубликовано John Wiley & Sons, Inc., Хобокен, Нью-Джерси, ISBN 978–0–470–17248–9.

[1] Браун, Том Б. и др. «Языковые модели — это немногие ученики». Препринт arXiv arXiv: 2005.14165 (2020).

[3] Специализация по машинному обучению. Доступно по адресу: https://in.coursera.org/specializations/machine-learning-introduction (дата обращения: 13 января 2023 г.).

[4] «Метод стохастической аппроксимации» Роббинса и Монро (1951), который представил алгоритм стохастического градиентного спуска.

[5] Данные предварительной обработки Доступно по адресу: https://scikit-learn.org/stable/modules/preprocessing.html#preprocessing-scaler) (дата обращения: 13 января 2023 г.).

[6] Цены на жилье — расширенные методы регрессии Доступно по адресу: https://www.kaggle.com/competitions/house-prices-advanced-regression-techniques/overview/description (дата обращения: 13 января 2023 г.) .