Я работаю над проблемой машинного обучения и хочу использовать линейную регрессию в качестве алгоритма обучения. Я реализовал 2 разных метода для нахождения параметров theta
модели линейной регрессии :градиента (наискорейшего )спуска и нормального уравнения. На одних и тех же данных они оба должны давать примерно равный theta
вектор. Однако это не так.
Оба вектора theta
очень похожи по всем элементам, кроме первого. Это тот, который используется для умножения вектора всего 1, добавленного к данным.
Вот как выглядят theta
s. (первый столбец является результатом градиентного спуска, второй вывод — нормальное уравнение):
Grad desc Norm eq
-237.7752 -4.6736
-5.8471 -5.8467
9.9174 9.9178
2.1135 2.1134
-1.5001 -1.5003
-37.8558 -37.8505
-1.1024 -1.1116
-19.2969 -19.2956
66.6423 66.6447
297.3666 296.7604
-741.9281 -744.1541
296.4649 296.3494
146.0304 144.4158
-2.9978 -2.9976
-0.8190 -0.8189
Что может вызвать разницу в theta(1, 1)
, возвращаемом градиентным спуском, по сравнению с theta(1, 1)
, возвращаемым нормальным уравнением? У меня есть ошибка в моем коде?
Вот моя реализация нормального уравнения в Matlab:
function theta = normalEque(X, y)
[m, n] = size(X);
X = [ones(m, 1), X];
theta = pinv(X'*X)*X'*y;
end
Вот код градиентного спуска:
function theta = gradientDesc(X, y)
options = optimset('GradObj', 'on', 'MaxIter', 9999);
[theta, ~, ~] = fminunc(@(t)(cost(t, X, y)),...
zeros(size(X, 2), 1), options);
end
function [J, grad] = cost(theta, X, y)
m = size(X, 1);
X = [ones(m, 1), X];
J = sum((X * theta - y).^ 2)./ (2*m);
for i = 1:size(theta, 1)
grad(i, 1) = sum((X * theta - y).* X(:, i))./ m;
end
end
Я передаю в обе функции одни и те же данные X
и y
(не нормализуюX
).
Основываясь на ответах и комментариях, я проверил немного своего кода и провел несколько тестов.
Сначала я хочу проверить, может ли проблема быть вызвана тем, что X почти единственное число, как это было предложено в ответе @user1489497 . Поэтому я заменил pinv на inv -, и при запуске я действительно получил предупреждение Matrix is close to singular or badly scaled.
. Чтобы убедиться, что это не проблема, я получил гораздо больший набор данных и провел тесты с этим новым набором данных. На этот раз inv(X)
не отображало предупреждение, и использование pinv
и inv
давало одинаковые результаты. Поэтому я надеюсь, чтоX
уже не близко к единственному числу .
Затем я изменил normalEque
код, предложенный на древесной щепе , так что теперь он выглядит так:
function theta = normalEque(X, y)
X = [ones(size(X, 1), 1), X];
theta = pinv(X)*y;
end
Однако проблема осталась . Новая функция normalEque
на новых данных, которые не близки к сингулярным, дает разные theta
как gradientDesc
.
Чтобы выяснить, какой алгоритм содержит ошибки, я запустил алгоритм линейной регрессии программного обеспечения для интеллектуального анализа данных Weka на тех же данных. Weka вычислил тета, очень похожий на вывод normalEque
, но отличающийся от вывода gradientDesc
. Итак, я предполагаю, что normalEque
правильный и вgradientDesc
есть ошибка..
Вот сравнение theta
s, вычисленных Weka, normalEque
и GradientDesc
:
Weka(correct) normalEque gradientDesc
779.8229 779.8163 302.7994
1.6571 1.6571 1.7064
1.8430 1.8431 2.3809
-1.5945 -1.5945 -1.5964
3.8190 3.8195 5.7486
-4.8265 -4.8284 -11.1071
-6.9000 -6.9006 -11.8924
-15.6956 -15.6958 -13.5411
43.5561 43.5571 31.5036
-44.5380 -44.5386 -26.5137
0.9935 0.9926 1.2153
-3.1556 -3.1576 -1.8517
-0.1927 -0.1919 -0.6583
2.9207 2.9227 1.5632
1.1713 1.1710 1.1622
0.1091 0.1093 0.0084
1.5768 1.5762 1.6318
-1.3968 -1.3958 -2.1131
0.6966 0.6963 0.5630
0.1990 0.1990 -0.2521
0.4624 0.4624 0.2921
-12.6013 -12.6014 -12.2014
-0.1328 -0.1328 -0.1359
. Я также вычислил ошибки, как это было предложено в ответе Джастина Пила . Выход normalEque
дает немного меньшую квадратичную ошибку, но разница незначительна. Более того , когда я вычисляю градиент стоимости theta
, используя функциюcost
(такой же, как тот, который используетсяgradientDesc
)Я получил градиент около нуля . То же самое, сделанное на выходе gradientDesc
, не дает градиент около нуля. Вот что я имею в виду:
>> [J_gd, grad_gd] = cost(theta_gd, X, y, size(X, 1));
>> [J_ne, grad_ne] = cost(theta_ne, X, y, size(X, 1));
>> disp([J_gd, J_ne])
120.9932 119.1469
>> disp([grad_gd, grad_ne])
-0.005172856743846 -0.000000000908598
-0.026126463200876 -0.000000135414602
-0.008365136595272 -0.000000140327001
-0.094516503056041 -0.000000169627717
-0.028805977931093 -0.000000045136985
-0.004761477661464 -0.000000005065103
-0.007389474786628 -0.000000005010731
0.065544198835505 -0.000000046847073
0.044205371015018 -0.000000046169012
0.089237705611538 -0.000000046081288
-0.042549228192766 -0.000000051458654
0.016339232547159 -0.000000037654965
-0.043200042729041 -0.000000051748545
0.013669010209370 -0.000000037399261
-0.036586854750176 -0.000000027931617
-0.004761447097231 -0.000000027168798
0.017311225027280 -0.000000039099380
0.005650124339593 -0.000000037005759
0.016225097484138 -0.000000039060168
-0.009176443862037 -0.000000012831350
0.055653840638386 -0.000000020855391
-0.002834810081935 -0.000000006540702
0.002794661393905 -0.000000032878097
Это предполагает, что градиентный спуск просто не сходится к глобальному минимуму...Но это вряд ли так, поскольку я запускаю его для тысяч итераций. Так где ошибка?