2015-05-02 4 views
1

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

Мои данные выборки:

df <- data.frame(c(1,5,6),c(3,5,6),c(4,6,8)) 

с С (4,6,8) быть значения у.

lm_gradient_descent <- function(df,learning_rate, y_col=length(df),scale=TRUE){ 

n_features <- length(df) #n_features is the number of features in the data set 

#using mean normalization to scale features 

if(scale==TRUE){ 

for (i in 1:(n_features)){ 
    df[,i] <- (df[,i]-mean(df[,i]))/sd(df[,i]) 
    } 
    } 
    y_data <- df[,y_col] 
    df[,y_col] <- NULL 
    par <- rep(1,n_features) 
    df <- merge(1,df) 
    data_mat <- data.matrix(df) 
    #we need a temp_arr to store each iteration of parameter values so that we can do a 
    #simultaneous update 
    temp_arr <- rep(0,n_features) 
    diff <- 1 
    while(diff>0.0000001){ 
    for (i in 1:(n_features)){ 
     temp_arr[i] <- par[i]-learning_rate*sum((data_mat%*%par-y_data)*df[,i])/length(y_data) 
    } 
    diff <- par[1]-temp_arr[1] 
    print(diff) 
    par <- temp_arr 
    } 

    return(par) 
} 

Выполнение этой функции

lm_gradient_descent(df,0.0001,,0) 

результаты, которые я получил, были

c(0.9165891,0.6115482,0.5652970) 

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

c(2,1,0). 

Надежда кто-то может пролить свет на то, куда я пошел rong в этой функции.

+0

Пожалуйста, добавьте ожидаемые и фактические результаты на ваш вопрос. – belwood

+0

@belwood, спасибо за ответ, я добавил результаты на вопрос. – xyy

ответ

0

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

old parameters - new parameters <= 0.0000001 

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

abs(old parameters - new parameters) <= 0.0000001 

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

+0

Большое вам спасибо за указание на это! Я попробовал гораздо меньший срок ошибки для критерия остановки (0.00000000000001), и я получил правильный ответ. Почему вы рекомендуете повторять итерирование для фиксированного количества итераций? Как я смогу выбрать подходящее количество итераций, чтобы я знал, что ответ сходится? Снова благодарим! – xyy

+0

@meri: Просто потому, что использование фиксированного количества итераций дает вам легкий винт для поворота, когда что-то не сходится. Трудно сформулировать критерий остановки, который будет работать в каждом случае. Вы также можете печатать среднюю квадратичную ошибку на каждой итерации, чтобы дать вам лучшее представление о том, что происходит. – cfh

+0

@meri: О, пожалуйста, не забывайте отмечать ответ как принятый, если он решил вашу проблему. – cfh

0

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

w_0 + w_1*x_1 + ... + w_n*x_n. 

Без w_0 срока, вы обычно не получите хороший результат.

+0

спасибо за ответ! Если я правильно понимаю вашу точку зрения, у меня должен быть термин перехвата, так как я добавил столбец из 1s в мою матрицу данных и использовал умножение матрицы в моей функции. С двумя независимыми переменными я должен вернуть 3 параметра. – xyy

+0

@meri: Извините, я пропустил это, я не читал R хорошо. Можете ли вы предоставить вывод из 'print (diff)' в своем вопросе? – cfh

0

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

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

Во-первых, в отношении ваших структур данных. Вы начинаете с кадра данных, переименовываете столбец, вычеркиваете вектор, а затем выделяете матрицу. Было бы намного проще начать с матрицы X (с заглавной буквы, поскольку ее компоненты «функции» называются x под номером i) и вектором решения y.

X <- cbind(c(1,5,6),c(3,5,6)) 
y <- c(4,6,8) 

Мы можем легко увидеть, какие решения требуются с масштабированием и без него путем установки модели линейной подгонки. (ПРИМЕЧАНИЕ Мы только масштаб X/функции, а не y/решения)

> lm(y~X) 

Call: 
lm(formula = y ~ X) 

Coefficients: 
(Intercept)   X1   X2 
     -4   -1   3 

> lm(y~scale(X)) 

Call: 
lm(formula = y ~ scale(X)) 

Coefficients: 
(Intercept) scale(X)1 scale(X)2 
     6.000  -2.646  4.583 

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

lm_gradient_descent <- function(X, y, learning_rate, scale=TRUE){ 

    if(scale==TRUE){X <- scale(X)} 

    X <- cbind(1, X) 

    theta <- rep(0, ncol(X)) #your old temp_arr 
    diff <- 1 
    old.error <- sum((X %*% theta - y)^2)/(2*length(y)) 
    while(diff>0.000000001){ 
    theta <- theta - learning_rate * t(X) %*% (X %*% theta - y)/length(y) 
    new.error <- sum((X %*% theta - y)^2)/(2*length(y)) 
    diff <- abs(old.error - new.error) 
    old.error <- new.error 
    } 
    return(theta) 
} 

И показать это работает ...

> lm_gradient_descent(X, y, .01, 0) 
      [,1] 
[1,] -3.9360685 
[2,] -0.9851775 
[3,] 2.9736566 

против ожидается (-4, -1, 3)

За что его ценность, хотя я согласен с @cfh, что я предпочел бы цикл с определенным номером итераций, я на самом деле не уверен, что вам нужна функция abs. Если diff < 0, то ваша функция не сходится.

Наконец, вместо того, чтобы использовать что-то вроде old.error и new.error Я бы предложил использовать вектор, который записывает все ошибки. Затем вы можете построить этот вектор, чтобы узнать, как быстро ваша функция сходится.