В чем заключается ошибка моего алгоритма градиентного спуска, построенного вручную? - PullRequest
0 голосов
/ 09 января 2020

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

Мой метод:

import pandas as pd
import numpy as np
import seaborn as sb
import matplotlib.pyplot as plt
from sklearn.linear_model import SGDRegressor

Data=pd.DataFrame({'X': list(np.arange(0,10,1)), 'Y': [1,3,2,5,7,8,8,9,10,12]})
Data.head()

sb.scatterplot(x ='X', y = 'Y', data = Data)
plt.show()

#generating column of ones
X0 = np.ones(len(Data)).reshape(-1,1)
#print(X0.shape)

X = Data.drop(['Y'], axis = 1).values
X_new = np.concatenate((X0,X), axis = 1)
#print(X_new)
#print(X_new.shape)

Y = Data.loc[:,['Y']].values
#print(Y)
#print(Y.shape)

# initial theta
theta =np.random.randint(low=0, high=1, size= X_new.shape[1]).reshape(-1,1)
#print(theta.shape)

J_history = []
theta_history = [list(theta.flatten())]

#gradient descent implementation
iterations = 1000
alpha = 0.01
m = len(Y)
for iter in range(1,iterations):
    H = X_new.dot(theta)
    loss = (H-Y)
    J = loss/(2*m)
    J_history.append(J)
    G = X_new.T.dot(loss)/m
    theta_new = theta - alpha*G    
    theta_history.append(list(theta_new.flatten()))
    theta = theta_new

# collecting costs (J) and coefficients (theta_0,theta_1)

theta_history.pop()
J_history = [i[0] for i in J_history]

params = pd.DataFrame()
params['J']=J_history

for i in range(len(theta_history[0])):
    params['theta_'+str(i)]=[k[i] for k in theta_history]

idx = params[params['J']==min(params['J'])].index
values = params.iloc[idx[0]][1:params.shape[1]].tolist()
print('intercept: {}, coeff: {}'.format(values[0],values[1]))

с использованием встроенной библиотеки:

import pandas as pd
import numpy as np
import seaborn as sb
import matplotlib.pyplot as plt
from sklearn.linear_model import SGDRegressor

Data=pd.DataFrame({'X': list(np.arange(0,10,1)), 'Y': [1,3,2,5,7,8,8,9,10,12]})
Data.head()

sb.scatterplot(x ='X', y = 'Y', data = Data)
plt.show()
model = SGDRegressor(loss = 'squared_loss', learning_rate = 'constant', eta0 = 0.01, max_iter= 1000)
model.fit(Data['X'].values.reshape(-1,1), Data['Y'].values.reshape(-1,1))
print('coeff: {}, intercept: {}'.format(model.coef_, model.intercept_))

1 Ответ

0 голосов
/ 09 января 2020

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

Теперь вернемся к вашему коду. Есть некоторые незначительные ошибки, которые необходимо исправить:

  • Ваши J s не скаляры, а numpy.array s, но то, как вы их используете, подразумевает, что они считаются скалярами следовательно ошибка возникла, когда ваш код выполняется.
  • После запуска вашей цепочки вы должны взять тета , у которого самая низкая ошибка, и эта ошибка на самом деле J ^ 2 , а не J поскольку J также может быть отрицательным.
  • Научение scikit SGDRegressor , которое вы на самом деле используете, как и предполагает его название, стохастично c по определению и учитывая небольшой размер вашего набора данных, вам нужно многократно запускать его и усреднять его оценки, если вы хотите получить что-то надежное из этого.
  • Скорость обучения 0,01 кажется немного большой

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

import pandas as pd
import numpy as np
import seaborn as sb
import matplotlib.pyplot as plt
from sklearn.linear_model import SGDRegressor

Data=pd.DataFrame({'X': list(np.arange(0,10,1)), 'Y': [1,3,2,5,7,8,8,9,10,12]})
Data.head()

sb.scatterplot(x ='X', y = 'Y', data = Data)
plt.show()


#generating column of ones
X0 = np.ones(len(Data)).reshape(-1,1)
#print(X0.shape)

X = Data.drop(['Y'], axis = 1).values
X_new = np.concatenate((X0,X), axis = 1)
#print(X_new)
#print(X_new.shape)

Y = Data.loc[:,['Y']].values
#print(Y)
#print(Y.shape)

# initial theta
theta =np.random.randint(low=0, high=1, size= X_new.shape[1]).reshape(-1,1)
#print(theta.shape)

J_history = []
theta_history = [list(theta.flatten())]

#gradient descent implementation
iterations = 2000
alpha = 0.001
m = len(Y)
for iter in range(1,iterations):
    H = X_new.dot(theta)
    loss = (H-Y)
    J = loss/(2*m)
    J_history.append(J[0]**2)
    G = X_new.T.dot(loss)/m
    theta_new = theta - alpha*G    
    theta_history.append(list(theta_new.flatten()))
    theta = theta_new
theta_history.pop()
J_history = [i[0] for i in J_history]


# collecting costs (J) and coefficients (theta_0,theta_1)

params = pd.DataFrame()
params['J']=J_history

for i in range(len(theta_history[0])):
    params['theta_'+str(i)]=[k[i] for k in theta_history]

idx = params[params['J']== params['J'].min()].index
values = params.iloc[idx[0]][1:params.shape[1]].tolist()
print('intercept: {}, coeff: {}'.format(values[0],values[1]))

#> intercept: 0.654041555750147, coeff: 1.2625626277290982


Теперь давайте посмотрим, как научится модель scikit


from sklearn.linear_model import SGDRegressor

intercepts = []
coefs = []
for _ in range(500):
    model = SGDRegressor(loss = 'squared_loss', learning_rate = 'constant',  eta0 = 0.01, max_iter= 1000)
    model.fit(Data['X'].values.reshape(-1,1), Data['Y'].values.reshape(-1))
    intercepts.append(model.intercept_)
    coefs.append(model.coef_)
intercept = np.concatenate(intercepts).mean()
coef = np.vstack(coefs).mean(0)
print('intercept: {}, coeff: {}'.format( intercept, coef))
#> intercept: 0.6912403374422401, coeff: [1.24932246]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...