Введение в алгоритмы
Линейная регрессия — один из самых простых алгоритмов регрессии. Простое введение в алгоритм: приведите пример двумерной плоскости. В математике средней школы можно найти прямую линию, если известны две точки. Ну и что, если дали 100 баллов. Как получить прямую? Невозможно уложить прямую линию в 100 точек. Должны быть ошибки, поэтому цель линейного программирования — уложить эти 100 точек прямой линией. минимизировать общую ошибку. Регрессия часто используется для изучения линейных отношений между целями и функциями. В основном используется для предиктивной аналитики.
Алгоритмическая сцена
Используем код для построения сценария использования алгоритма.Сначала определим n точек. Посмотрите на распределение этих n точек.
from sklearn.datasets import load_diabetes
import matplotlib.pyplot as plt
import numpy as np
X = np.arange(0,10,0.05).reshape(-1, 1)
np.random.seed(100)
y = 0.5 * np.arange(0,10,0.05) + 3 + np.random.rand(len(X))
plt.scatter(X.reshape(1, -1), y)
Результат показан ниже:
Можно видеть, что n точек, которые мы намеренно построили, вероятно, находятся околоЭта прямая распределена.
Так что теперь есть проблема, если дана новая точка, абсцисса, пожалуйста, предскажите ординату.
Модель алгоритма
На предыдущем шаге мы уже знали, что для набора точек, распределенных по определенному линейному закону, нам нужно использовать прямую линию, чтобы подогнать этот набор выборок.
Сначала предположим, что образец составляет около
Эта линия распределена.представляет прогнозируемое значение. Тогда задача решения модели линейной регрессии трансформируется в решение параметрови.
Как упоминалось на предыдущем шаге, цель линейной регрессии — найти такую линию, которая минимизирует ошибку во всех точках. Какие критерии мы используем для выражения «ошибки», чтобы найти наилучшие параметры?
Теперь мы знаем, что характеристики определенного образца. Одновременные образцысоответствующее целевое значениетакже известно.
Мы используем параметриРассчитать прогнозируемое значение:
Затем определите потери для одной точки
То есть квадрат расстояния между истинным значением и прогнозируемым значением. Тогда сумма ошибок n точек будет следующей:
Подставив параметры, получим:
Это функция потерь, которую мы собираемся определить. Итак, теперь проблема трансформировалась в
то есть решитьи ${b} заставляют функцию потерь иметь минимальное значение.
решение модели
Существует два распространенных способа решения моделей линейной регрессии: (1) метод наименьших квадратов (2) алгоритм градиентного спуска.
Метод наименьших квадратов прост для решения, идея состоит в том, чтобы вычислитьк производной, так что формула равна 0. В этом случае формула имеет минимальное значение. Детали пока не обсуждаются.
Так как алгоритм градиентного спуска имеет более широкий спектр сценариев использования, мы также используем алгоритм градиентного спуска для его решения.
Алгоритм градиентного спуска решает процесс линейной регрессии:
(1) Инициализацияиявляется небольшим значением, не равным 0.
(2) с токомиРешение для предсказанных значений.
(3) Если прогнозируемое значениеи фактическое значение прогнозируемое значениеошибка больше, чем, перейдите к (4); если прогнозируемое значениеи фактическое значение прогнозируемое значениеошибка меньше чем, возвращает текущийи. Решение заканчивается. (4) Решите частную производную функции потерь и обновите параметрыи:
Реализуйте алгоритм градиентного спуска самостоятельно
class LinearRegression:
def __init__(self, eta=0.02, n_iters = 1e4, epsilon = 1e-3):
self._theta = None
self._eta = eta
self._n_iters = n_iters
self._epsilon = epsilon
def Cost(self, theta, X_b, y):
try:
return np.sum(np.square(y - X_b.dot(theta))) / len(X_b)
except:
return float('inf')
def dCost(self, theta, X_b, y):
return (X_b.dot(theta) - y).dot(X_b) * 2 / len(X_b)
def gradient_descent(self, X_b, y, initial_theta, eta, n_iters, epsilon):
theta = initial_theta
eta = self._eta
n_iters = self._n_iters
epsilon = self._epsilon
i_iter = 0
try:
while i_iter < n_iters:
gradient = self.dCost(theta, X_b, y)
last_theta = theta
theta = theta - eta * gradient
diff = abs(self.Cost(theta, X_b, y) - self.Cost(last_theta, X_b, y))
if (diff > 1e100):
print('eta is too large!')
break
if (diff < epsilon):
break
i_iter += 1
self._theta = theta
except:
self._theta = float('inf')
return self
def fit(self, X_train, y_train):
assert X_train.shape[0] == y_train.shape[0], 'train data has wrong dimenssion'
self._X_train = X_train
self._y_train = y_train
X_b = np.hstack([np.ones((len(self._X_train), 1)), self._X_train])
initial_theta = np.zeros(X_b.shape[1])
eta = 0.01
self.gradient_descent(X_b, y_train, initial_theta, self._eta, self._n_iters, self._epsilon)
return self
def predict(self, X_test):
X_b = np.hstack([np.ones((len(X_test), 1)), X_test])
return np.dot(X_b, self._theta)
Приведенный выше код сохраняется в виде отдельного файла, на который можно ссылаться и вызывать его позже. Уведомление в нашей модели
в соответствующем коде
В нашей модели с одной функцией это на самом деле:
После матричных операций можно найти, что
Левая часть уравнения представляет собой представление в модели, а правая часть уравнения представляет собой представление в коде Это сделано для облегчения матричных операций.
Вызов модели линейного программирования, написанной вами
linear_regression = LinearRegression(
epsilon = 1e-6,
eta = 0.02
)
linear_regression.fit(X_train, y_train)
y_predict = linear_regression.predict(X_test)
params = linear_regression._theta
Результат выглядит следующим образом:
array([3.45402168, 0.51257892])
То есть решение получается:
На самом деле, она очень близка к кривой распределения при первоначальном построении этой партии образцов. Нарисуем точки и линии на одном графике и посмотрим на эффект:
plt.scatter(X.reshape(1, -1), y)
theta = params[1]
b = params[0]
X = np.arange(0,10,0.05).reshape(-1, 1)
y_predict = theta * X + b
plt.scatter(X, y_predict)
Результат выглядит следующим образом:
На самом деле эта партия образцов была хорошо подогнана.
Уведомление:
Значение eta должно быть соответствующим. Если значение слишком мало, результат будет слишком медленным для сходимости. После выполнения заданного количества итераций он не сошелся к нужному нам значению; если он слишком велик, он не только не сойдётся, но и произойдёт взрывное расхождение.
эпсилон - это диапазон ошибки, который мы даем, когда ошибка эпсилон меньше определенного значения, мы думаем, что прямая линия удовлетворила точность подгонки.
Вызов модели линейного программирования в sklearn
Далее вызовем модель в sklearn, чтобы увидеть эффект:
from sklearn.linear_model import LinearRegression
linear_regression = LinearRegression()
linear_regression.fit(X_train, y_train)
y_predict = linear_regression.predict(X_test)
linear_regression.coef_, linear_regression.intercept_
Результат выглядит следующим образом:
(array([0.51042252]), 3.4682654875517605)
То есть через линейную модель в sklearn получается решение:
Взгляните на график подгонки:
Результаты оказались неразличимы невооруженным глазом.
При вызове модели линейного программирования в sklearn мы не задавали конкретных параметров и использовали параметры по умолчанию. Обнаружено, что результаты, полученные с помощью нашей собственной модели, по-прежнему сильно отличаются от модели в sklearn, и существует определенная ошибка, поскольку необязательные параметры двух моделей несовместимы. Если значения различных параметров будут одинаковыми, я думаю, результаты будут ближе.
Суммировать
Линейное программирование — относительно простой для понимания алгоритм. В данной статье представлен только алгоритм градиентного спуска, студенты, интересующиеся методом наименьших квадратов, могут изучить его самостоятельно.