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

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

Мы начнем с определения набора данных, который мы будем использовать в этом курсе, мы будем использовать простую формулировку количественной переменной Y, которую мы определим следующим образом:

Для генерации и визуализации данных в python мы можем использовать следующий код:

import numpy as np
from matplotlib import pyplot as plt
#Creating the dataset
N=100
x = np.linspace(0,1,N)
y = 1.5*x-0.8
#Plot the dataset
plt.xlabel("x")
plt.ylabel("y");
plt.grid(True, which='both')
plt.scatter(x,y)

Код сгенерирует следующий график,

Теперь предположим, что вы получили этот набор данных и понятия не имеете, как он был сгенерирован, тогда вас попросят предсказать для нового значения x, каким будет приблизительное значение y, например, на этом графике, каким будет значение y, когда x равно 1,5, что нельзя вывести из графика.

Первый интуитивный способ решить эту проблему — просто попытаться смоделировать переменную Y с помощью функции, которую мы обозначим h и которая более формально зависит от x.

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

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

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

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

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

Математически функцию стоимости J можно сформулировать следующим образом:

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

Давайте визуализируем значение функции стоимости для разных пар параметров, мы будем использовать следующий код Python:

import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
def costfunction(X,y,theta):
   m = np.size(y)
   #Cost function in vectorized form
   h = X @ the
   J = float((1./(2*m)) * (h - y).T @ (h - y));
   return J;
def gradient_descent(X,y,theta,alpha = 0.0005,num_iters=1000):
  #Initialisation of useful values
  m = np.size(y)
  J_history = np.zeros(num_iters)
  theta_0_hist, theta_1_hist = [], [] #For plotting afterwards
  for i in range(num_iters):
    #Grad function in vectorized form
    h = X @ theta
    theta = theta - alpha * (1/m)* (X.T @ (h-y))
    
    #Cost and intermediate values for each iteration
    J_history[i] = costfunction(X,y,theta)
    theta_0_hist.append(theta[0,0])
    theta_1_hist.append(theta[1,0])
  return theta,J_history, theta_0_hist, theta_1_hist
#Creating the dataset
N=100
x = np.linspace(0,1,N)
y = 1.5*x-0.8
y = y.reshape(-1,1)
X = np.vstack((np.ones(len(x)),x)).T
#Setup of meshgrid of theta values
T0, T1 = np.meshgrid(np.linspace(-1,3,100),np.linspace(-6,2,100))
#Computing the cost function for each theta combination
zs = np.array(  [costfunction(X, y.reshape(-1,1),np.array([t0,t1]).reshape(-1,1))
for t0, t1 in zip(np.ravel(T0), np.ravel(T1)) ] )
#Reshaping the cost values
Z = zs.reshape(T0.shape)
#Computing the gradient descent
theta_result,J_history, theta_0, theta_1 = gradient_descent(X,y,np.array([0,-6]).reshape(-1,1),alpha = 0.3,num_iters=1000)
#Angles needed for quiver plot
anglesx = np.array(theta_0)[1:] - np.array(theta_0)[:-1]
anglesy = np.array(theta_1)[1:] - np.array(theta_1)[:-1]
%matplotlib inline
fig = plt.figure(figsize = (16,8))
#Surface plot
ax = fig.add_subplot(1, 2, 1, projection='3d')
ax.plot_surface(T0, T1, Z, rstride = 5, cstride = 5, cmap = 'jet', alpha=0.5)
#ax.plot(theta_0,theta_1,J_history, marker = '*', color = 'r', alpha = .4, label = 'Gradient descent')
ax.set_xlabel(r'\theta_0')
ax.set_ylabel(r'\theta_1')
ax.set_zlabel('Cost function')
ax.view_init(45, 45)
#Contour plot
ax = fig.add_subplot(1, 2, 2)
ax.contour(T0, T1, Z, 70, cmap = 'jet')
#ax.quiver(theta_0[:-1], theta_1[:-1], anglesx, anglesy, scale_units = 'xy', angles = 'xy', scale = 1, color = 'r', alpha = .9)
plt.savefig('2.png',dpi=100)
The code will generate the following plot,

On the left we can see the surface in 3d which gives for each pair of parameters the value of the cost function and on the right we have the contour plot which is defined as follows according to wikepedia.

«Контурная линия (также изолиния, изоплет или изарифм) функции двух переменных — это кривая, вдоль которой функция имеет постоянное значение, так что кривая соединяет точки равного значения». Википедия.

Получив этот график, мы можем непосредственно посмотреть на минимум функции стоимости, который в нашем случае находится в точке (-0,8, 1,49), что даст нам значение двух параметров, которые лучше всего соответствуют нашим данным:

И теперь мы можем использовать эту функцию, чтобы предсказать значение y для новых значений x, которых нет в нашем наборе данных. Например, значение y при x равно 1,5 следующим образом:

Поэтому мы можем предположить, что если x равно 1,5, y будет равно 1,435.

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

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

Вывод

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

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