天天看点

【多变量线性回归】学习记录序思路实现终

由于最近时间比较紧,要学的东西也比较多,所以这篇文章会写得比较粗略,主要目的也是保存自己的代码,以及方便自己日后回忆。

思路

J 函数

首先我们将要定义一个 J J J 函数,意在表达当前函数与训练数据间的差异值, J J J 函数的值越大,表示在参数为 θ \theta θ 时当前函数 h θ ( x ) h_{\theta}(x) hθ​(x) 与训练数据 y y y 的拟合程度越差。下面给出 J J J 函数的定义式:

J θ = 1 2 m ∗ ∑ i = 1 m ( h θ ( x ( i ) ) − y ( i ) ) J_{\theta} = \frac {1} {2m} * \sum_{i=1}^{m} {(h_{\theta}(x^{(i)})-y^{(i)})} Jθ​=2m1​∗i=1∑m​(hθ​(x(i))−y(i))

J J J 函数有一些喜人的性质,比如局部最优解等于全局最优解,正是这个性质使得我们可以放心地使用梯度下降算法来训练算法。

下面是 J J J 函数关于 θ \theta θ 值的 surf 图和 contour 图,图三中的 mark 表示经过数次学习后使 J J J 函数达到收敛的参数的所在位置。

【多变量线性回归】学习记录序思路实现终
【多变量线性回归】学习记录序思路实现终

梯度下降

可以被想象为一个小球处于某个初始状态,不断向山谷即极小值点滚动的过程。这里的山谷指的是 J J J 函数的值关于 θ \theta θ 的变化。

θ j = θ j − α 1 m ∑ i = 1 m ( h θ ( x ( i ) ) − y ( i ) ) x j ( i ) \theta_{j} = \theta_{j} - \alpha \frac {1} {m} \sum_{i=1}^m {(h_{\theta}(x^{(i)})-y^{(i)})} x^{(i)}_j θj​=θj​−αm1​i=1∑m​(hθ​(x(i))−y(i))xj(i)​

向量化

内置的向量库要比手写循环快很多,所以代码实现的时候尽可能用向量表示。

实现

主脚本(my_mul.m)

clear;
close all;
clc;

% ====================================================

fprintf('load the ex1data2.txt...\n');
data = load('ex1data2.txt');
X = data(:, 1:2);
y = data(:, 3);

m = length(y); % number of sample case
fprintf('load successful!\n\n\n');


fprintf('init the data...\n');
[X, mu, stdd] = init_data(X);
X = [ones(m,1), X];
fprintf('init successful!\n\n\n');

% ====================================================

theta = [0; 0; 0];
alpha = 0.2;
iteration = 50;
fprintf('init the parameter, successful!\n');

[theta, J_his] = gra_des(X, y, theta, alpha, iteration);
cur_J = J_his(size(J_his), 1);
fprintf('cur_J = %f\n',cur_J);

plot((1:50), J_his(:, 1));

query = [1650, 3];
query = [ones(1,1), (query - mu) ./ stdd * 3];
tmp = query * theta;

fprintf('Predicted price of a 1650 sq-ft, 3 br house is %f\n',tmp);

           

数据初始化(init_data.m)

为了避免各个维度的数据之间相差过大,梯度下降时不收敛,把所有数据通过加减和缩放变为均值为 0,标准差为 1 的数据。并把缩放记录保存下来,在预测其他数据时需要使用。

function [res, mu, stdd] = init_data(X) 
	mu = mean(X); minn = min(X); maxx = max(X);
	stdd = maxx - minn;
	for i = 1:size(X, 2)
		X(:, i) = X(:, i) - mu(1, i);
		if maxx(1, i) ~= minn(1, i)
			X(:, i) = X(:, i) / stdd(1, i) * 3;
		end;
	end;
	res = X;
	
           

计算 J函数 (calc_J.m)

这个很简单,不多bb。

function J = calc_J(X, y, theta)
	m = length(y);
	J = 0;
	J = 1/(2*m) * sum(((X*theta)-y).^2);
	
           

梯度下降 (gra_des.m)

把 J J J 函数的变化曲线也保存下来,这样调 α \alpha α (学习速率) 的时候很方便。

function [theta, J_his] = gra_des(X, y, theta, alpha, iteration) 
	m = length(y);
	J_his = zeros(m, 1);

	for iter = 1:iteration
		theta = theta - (alpha/m) * (X'*(X*theta-y));
		J_his(iter, 1) = calc_J(X, y, theta);
	end;

           

现在一看简单得一匹,我为什么当时实现了那么久?

继续阅读