簡述
最近在coursera上看Stanford的經(jīng)典機器學(xué)習(xí)課程,總體上感覺跟國內(nèi)某大學(xué)的研究生課程內(nèi)容其實差不多墙贱。先從經(jīng)典的線性回歸模型開始寫起吧叙淌。本文的模型實例來自于課程練習(xí)——根據(jù)房屋大小和房屋數(shù)量的統(tǒng)計數(shù)據(jù)來預(yù)估某房產(chǎn)的售價底挫,多元線性回歸的數(shù)據(jù)集在ex1data2文件中可以找到寿烟,一元數(shù)據(jù)集在ex1data1中。
PS:由于一元線性回歸也屬于一種特殊的多元線性回歸走搁,我決定偷懶直接上多元線性回歸独柑。
算法過程
主要包括幾個方面:
- 數(shù)據(jù)清理(本例中主要是feature normalize)
- 算法
- gradient descent(梯度下降)
- normal equation(正規(guī)方程)
數(shù)據(jù)清理
主要是讓數(shù)據(jù)集處于一種“密集穩(wěn)定”的狀態(tài),否則不經(jīng)過整理的數(shù)據(jù)集會讓你在選擇學(xué)習(xí)率的時候異常尷尬私植。(我親自試過忌栅,你也可以試試不清理數(shù)據(jù)直接用梯度下降,看看會發(fā)生什么)不整理數(shù)據(jù)曲稼,有時候你可能會只能選用非常小的學(xué)習(xí)率狂秘,才能保證梯度下降的時候不會“跑飛”。(迭代到不收斂)然而這個學(xué)習(xí)率可能會非常的小躯肌,導(dǎo)致你在訓(xùn)練的時候者春,可能要迭代幾千萬次才能訓(xùn)練一點點,甚至根本無法訓(xùn)練清女。
一般來說钱烟,我們選擇將數(shù)據(jù)“正態(tài)化”.根據(jù)統(tǒng)計學(xué)基礎(chǔ)知識,算出均值和標(biāo)準(zhǔn)差嫡丙,使得數(shù)據(jù)呈標(biāo)準(zhǔn)正態(tài)分布即可拴袭。在matlab中,均值函數(shù)為mean()
,標(biāo)準(zhǔn)差函數(shù)為std()
曙博。
梯度下降
想要使用一個線性方程來擬合數(shù)據(jù)集拥刻,當(dāng)數(shù)據(jù)集是N元的時候,則需要選擇N個變量來與這些未知數(shù)組成線性方程父泳,這N個變量記作theta般哼。在迭代的首次吴汪,當(dāng)然可以隨意選擇一組未知數(shù)開始。
接下來蒸眠,就是選擇一個代價函數(shù)cost()
漾橙,注意此函數(shù)的自變量當(dāng)然是N個theta,使得代價函數(shù)最欣憧ā(與實際情況擬合的最好)霜运。一般來說,我們選擇最小二乘法來判斷代價的大小蒋腮。
接下來淘捡,為了判斷N元函數(shù)cost()
的最小值點,就是一個求導(dǎo)的過程了池摧。這里要插一句題外話焦除,線性回歸代價函數(shù)的最小值就是極小值,因此不存在迭代到某個極小值之后卡死在某點而不能繼續(xù)尋找最小值的情況险绘,具體的可以自己證明踢京。
梯度下降算法采用了梯度的概念誉碴,在某點沿著梯度的方向移動一小段距離宦棺,然后重復(fù)迭代這個過程,直到完成收斂黔帕。
正規(guī)方程
正規(guī)方程前面與梯度下降一樣代咸,只不過最小二乘擬合的答案直接通過數(shù)學(xué)方法由線性代數(shù)方程解出來。優(yōu)點是:不需要迭代成黄,不需要清理數(shù)據(jù)(因為不需要調(diào)整學(xué)習(xí)率呐芥,所以自然不需要整理數(shù)據(jù)呀),程序?qū)懫饋矸浅:唵畏芩辍H秉c是:當(dāng)參數(shù)過多的時候思瘟,逆矩陣運算量太大;當(dāng)參數(shù)存在線性關(guān)系的時候闻伶,逆矩陣當(dāng)然是不存在的~這個時候你沒法求逆矩陣了(當(dāng)然可以用偽逆矩陣來求滨攻,但是不推薦)。不過就我個人經(jīng)驗而言蓝翰,一般來說參數(shù)不太可能會出現(xiàn)線性相關(guān)的情況光绕。如果出現(xiàn)了,可能會存在意義有重復(fù)參數(shù)畜份,這個時候就要清理一下數(shù)據(jù)集诞帐,把不必要的參數(shù)項給去掉,就不會求解的時候出現(xiàn)矩陣不可逆的尷尬情況了爆雹。
程序
程序使用matlab寫的停蕉,coursera是可以提交答案的~具體的提交方法可以參考pdf說明愕鼓。
多元線性回歸的主函數(shù):
%% Initialization
%% ================ Part 1: Feature Normalization ================
%% Clear and Close Figures
clear ; close all; clc
fprintf('Loading data ...\n');
%% Load Data
data = load('ex1data2.txt');
X = data(:, 1:2);
y = data(:, 3);
m = length(y);
% Print out some data points
fprintf('First 10 examples from the dataset: \n');
fprintf(' x = [%.0f %.0f], y = %.0f \n', [X(1:10,:) y(1:10,:)]');
fprintf('Program paused. Press enter to continue.\n');
pause;
% Scale features and set them to zero mean
fprintf('Normalizing Features ...\n');
[X, mu, sigma] = featureNormalize(X);
% Add intercept term to X
X = [ones(m, 1) X];
std(X(:,2))
std(X(:,2))
X(:,2)
%% ================ Part 2: Gradient Descent ================
fprintf('Running gradient descent ...\n');
% Choose some alpha value
alpha = 0.01;
num_iters = 400;
% Init Theta and Run Gradient Descent
theta = zeros(3, 1);
computeCostMulti(X,y,theta)
[theta, J_history] = gradientDescentMulti(X, y, theta, alpha, num_iters);
% Plot the convergence graph
figure;
plot(1:numel(J_history), J_history, '-b', 'LineWidth', 2);
xlabel('Number of iterations');
ylabel('Cost J');
% Display gradient descent's result
fprintf('Theta computed from gradient descent: \n');
fprintf(' %f \n', theta);
fprintf('\n');
% Estimate the price of a 1650 sq-ft, 3 br house
% Recall that the first column of X is all-ones. Thus, it does
% not need to be normalized.
price = 0; % You should change this
parameter = [1650,3];
parameter = (parameter-mu)./sigma;
parameter = [1,parameter];
price = theta'*parameter';
fprintf(['Predicted price of a 1650 sq-ft, 3 br house ' ...
'(using gradient descent):\n $%f\n'], price);
fprintf('Program paused. Press enter to continue.\n');
pause;
%% ================ Part 3: Normal Equations ================
fprintf('Solving with normal equations...\n');
%% Load Data
data = csvread('ex1data2.txt');
X = data(:, 1:2);
y = data(:, 3);
m = length(y);
% Add intercept term to X
X = [ones(m, 1) X];
% Calculate the parameters from the normal equation
theta = normalEqn(X, y);
% Display normal equation's result
fprintf('Theta computed from the normal equations: \n');
fprintf(' %f \n', theta);
fprintf('\n');
% Estimate the price of a 1650 sq-ft, 3 br house
price = 0; % You should change this
parameter = [1,1650,3];
price = theta'*parameter';
fprintf(['Predicted price of a 1650 sq-ft, 3 br house ' ...
'(using normal equations):\n $%f\n'], price);
多元線性回歸的梯度下降函數(shù):
function [theta, J_history] = gradientDescentMulti(X, y, theta, alpha, num_iters)
% Initialize some useful values
m = length(y); % number of training examples
J_history = zeros(num_iters, 1);
for iter = 1:num_iters
delta = zeros(size(X,2),1);
for i=1:size(X,2)
delta(i,1)=sum((theta'*X'-y').*(X(:,i))')*alpha/m;
end
theta = theta - delta;
% Save the cost J in every iteration
J_history(iter) = computeCostMulti(X, y, theta);
end
end
數(shù)據(jù)正態(tài)化整理:
function [X_norm, mu, sigma] = featureNormalize(X)
X_norm = X;
mu = zeros(1, size(X, 2));
sigma = zeros(1, size(X, 2));
for i=1:size(X,2)
mu(1,i)=mean(X(:,i));
sigma(1,i)=std(X(:,i));
end
for i=1:size(X,2)
X_norm(:,i)= (X_norm(:,i)-mu(1,i))/sigma(1,i);
end
end
正規(guī)方程函數(shù):
function [theta] = normalEqn(X, y)
theta = zeros(size(X, 2), 1);
theta = (X'*X)^(-1)*X'*y;
end
總結(jié)
總體來說,是一個比較簡單的算法谷徙,高等數(shù)學(xué)和線性代數(shù)基礎(chǔ)扎實的同學(xué)理解起來應(yīng)該非常容易拒啰。