1.Logistic Regression
在逻辑回归中,已知样本的输出y只有0和1两个结果。我们可以通过对已知样本的训练得到一个分类器,使之可以预测新的样本的类别。
1.1Visualizing the data
由于输出y只有两个结果,所以可以通过 find() 函数得到对应的坐标。
pos=find(y==1);
neg=find(y==0);
结果如图:
坐标已知时,使用 plot() 函数绘制,并根据结果选择合适的样式。
plot(X(pos,1),X(pos,2),"k+","LineWidth",2,"MarkerSize",7);
hold on
plot(X(neg,1),X(neg,2),"ko","MarkerFaceColor",'y',"MarkerSize",7);
结果如图
1.2 Implementation
与线性回归的差别在于,逻辑回归的假设函数
h
θ
(
x
)
h_\theta(x)
hθ(x)取值在0和1之间。
h
θ
(
x
)
=
1
1
+
e
−
θ
T
X
\ h_\theta(x)=\frac{1}{1+e^{{-\theta}^{ T}X}}
hθ(x)=1+e−θTX1
推导:
彻底搞懂逻辑回归
1.2.1 Sigmoid Function
g
(
z
)
=
1
1
+
e
−
z
\ g(z)=\frac {1}{1+e^{-z}}
g(z)=1+e−z1
写代码时应保证函数对向量/矩阵输入仍有效。因为是对向量的每一个元素进行运算,所以是点乘“.*”。
g=1./(1.+exp(-1.*z));
1.2.2 CostFunction and Gradient
代价函数可以理解成假设函数与实际输出有偏差时所受到的惩罚,当然,差别越大惩罚越大。在逻辑回归中,形式为:
J
(
θ
)
=
1
m
∑
i
=
1
m
[
−
y
(
i
)
log
(
h
θ
(
x
(
i
)
)
)
−
(
1
−
y
(
i
)
)
log
(
1
−
h
θ
(
x
(
i
)
)
)
]
\ J(\theta) =\frac{1}{m}\sum_{i=1}^m{\left[-y^{(i)} \log(h_{\theta}(x^{(i)}))- (1 -y^{(i)}) \log(1- h_{\theta}(x^{(i)}))\right]}
J(θ)=m1i=1∑m[−y(i)log(hθ(x(i)))−(1−y(i))log(1−hθ(x(i)))]
对每个参数
θ
j
\theta_j
θj求偏导,即求代价函数的梯度:
∂
J
(
θ
)
∂
θ
j
=
1
m
∑
i
=
1
m
(
h
θ
(
x
(
i
)
)
−
y
(
i
)
)
x
j
(
i
)
\ \frac{\partial J(\theta)}{\partial \theta_j} = \frac{1}{m}\sum_{i=1}^m{\left( h_\theta(x^{(i)})-y^{(i)}\right)x_j^{(i)}}
∂θj∂J(θ)=m1i=1∑m(hθ(x(i))−y(i))xj(i)
注意:梯度表达式虽然在形式上和线性回归的梯度表达式一致,但两者假设函数不同。
J=-1/m*sum(y.*log(sigmoid(X*theta))+(1.-y).*log(1.-sigmoid(X*theta)));
grad=1/m*sum((sigmoid(X*theta)-y).*X);
1.2.3 Learning parameters using fminunc
梯度下降算法虽然有效,需要人为设置学习率
α
\alpha
α,而且其值过小时会导致代价函数收敛过慢,过大时会导致可能无法收敛。因此我们考虑更好的优化算法,如fminunc()。在使用这个函数时,我们无需自己写循环或者设置学习率,只需要写出计算代价函数和梯度的函数即可。
fminunc() 是matlab的一个内置函数,用来求无约束多变量函数的最小值。
(无约束:指自变量除了目标函数外,没有其他的约束条件,如
θ
<
1
\theta<1
θ<1。因此这些参数可以取任意值。)
fminunc()函数的详细介绍
运行代码:
% Set options for fminunc
options = optimoptions(@fminunc,'Algorithm','Quasi-Newton','GradObj', 'on', 'MaxIter', 400);
% Run fminunc to obtain the optimal theta
% This function will return theta and the cost
[theta, cost] = fminunc(@(t)(costFunction(t, X, y)), initial_theta, options);
% Print theta
fprintf('Cost at theta found by fminunc: %f\n', cost);
disp('theta:');disp(theta);
% Plot Boundary
plotDecisionBoundary(theta, X, y);
% Add some labels
hold on;
% Labels and Legend
xlabel('Exam 1 score')
ylabel('Exam 2 score')
% Specified in plot order
legend('Admitted', 'Not admitted')
hold off;
运行上面的代码,就会调用我们自己写的costFunction()函数,计算得最优解,并根据求得的参数绘制出决策边界:
1.2.4 Evaluating logistic regression
为了评价我们训练出来的分类器的性能,我们需要设计一个评估程序。功能是:对于训练集中的样本,我们可以判断输出结果为0或者1,并与正确结果进行比较,就可以得到分类的成功率。
对于0和1的分类问题,我们可以设置0.5为临界值,即大于0.5则认为其倾向于1,我们便判断结果为1;同样小于0.5时认为结果输出为0。这一点从假设函数函数中也可以看出来。
这里可以先计算出sgimoid(
θ
\theta
θX)的值,然后进行四舍五入即可。
matlab里整数类型默认为双精度浮点数double类型,我们直接进行类型转换。
result=sigmoid(X*theta);
p=int8(result);
这样便得到我们训练的分类器对于对应样本的预测值。结果如图:
在判断成功率时,练习程序给出了很好的思路:
fprintf('Train Accuracy: %f\n', mean(double(p == y)) * 100);
mean(A);可以返回数组元素的均值。完成程序如下:
% Predict probability for a student with score 45 on exam 1 and score 85 on exam 2
prob = sigmoid([1 45 85] * theta);
fprintf('For a student with scores 45 and 85, we predict an admission probability of %f\n\n', prob);
% Compute accuracy on our training set
p = predict(theta, X);
fprintf('Train Accuracy: %f\n', mean(double(p == y)) * 100);
结果为:
2.Regularization logistic regression
当参数过多时,假设函数可能与训练集拟合的很好,代价函数的结果也很小,但是无法泛化(generalize)到新的样本中,称为过拟合问题。
正则化的思想可以解决过拟合问题。
2.1 Visualizing the data
由于plotData() 函数已经写好,因此直接调用即可。
% The first two columns contains the X values and the third column
% contains the label (y).
data = load('ex2data2.txt');
X = data(:, [1, 2]); y = data(:, 3);
plotData(X, y);
% Put some labels
hold on;
% Labels and Legend
xlabel('Microchip Test 1')
ylabel('Microchip Test 2')
% Specified in plot order
legend('y = 1', 'y = 0')
hold off;
得到结果:
2.2 Feature mapping
在使假设函数拟合训练集的过程中,为了拟合的更好,有一种思路是为每一个数据添加更多的特征,往往是不同阶次的组合,如下图所示。这样做的结果是使参数向量由二维
[
x
1
;
x
2
]
[x_1;x_2]
[x1;x2]变成一个28维的向量。由于维数的提高,决策边界也将更复杂。
正如前面提到的,过多的特征会使假设函数与训练集拟合的更好,但可能无法泛化到新的样本中,因此需要加入正则项。
2.3 CostFunction and gradient
考虑到拟合的过程是一个使代价函数最小的过程,因此我们在代价函数中添加正则项,对参数进行“惩罚”,以使参数的值不会过大。也就是说,对于阶次更高的特征,其对应的参数因为会受到更大的惩罚而变小,这样就降低了高阶特征对于假设函数的影响。
代价函数:
J
(
θ
)
=
1
m
∑
i
=
1
m
[
−
y
(
i
)
log
(
h
θ
(
x
(
i
)
)
)
−
(
1
−
y
(
i
)
)
log
(
1
−
h
θ
(
x
(
i
)
)
)
]
+
λ
2
m
∑
j
=
1
n
θ
j
2
\ J(\theta) =\frac{1}{m}\sum_{i=1}^m{\left[-y^{(i)} \log(h_{\theta}(x^{(i)}))-(1-y^{(i)}) \log(1-h_{\theta}(x^{(i)}))\right]+\frac{\lambda}{2m}\sum_{j=1}^n{\theta_j^2}}
J(θ)=m1i=1∑m[−y(i)log(hθ(x(i)))−(1−y(i))log(1−hθ(x(i)))]+2mλj=1∑nθj2
其中
λ
\lambda
λ为正则化参数。注意对于参数
θ
0
\theta_0
θ0无需正则化,因为其作为常数项,不会对曲线形状有影响。
对代价函数做修改后,梯度表达式也应该修改:
∂
J
(
θ
)
∂
θ
j
=
1
m
∑
i
=
1
m
(
h
θ
(
x
(
i
)
)
−
y
(
i
)
)
x
j
(
i
)
f
o
r
j
=
0
\ \frac{\partial J(\theta)}{\partial \theta_j} = \frac{1}{m}\sum_{i=1}^m{\left( h_\theta(x^{(i)})-y^{(i)}\right)x_j^{(i)}\qquad \mathrm{for}\;j=0}
∂θj∂J(θ)=m1i=1∑m(hθ(x(i))−y(i))xj(i)forj=0
∂
J
(
θ
)
∂
θ
j
=
(
1
m
∑
i
=
1
m
(
h
θ
(
x
(
i
)
)
−
y
(
i
)
)
x
j
(
i
)
)
+
λ
m
θ
j
f
o
r
j
≥
1
\ \frac{\partial J(\theta)}{\partial \theta_j} = \left( \frac{1}{m}\sum_{i=1}^m{\left( h_\theta(x^{(i)})-y^{(i)}\right)x_j^{(i)}} \right)+\frac{\lambda}{m}\theta_j\qquad \mathrm{for}\;j\geq1
∂θj∂J(θ)=(m1i=1∑m(hθ(x(i))−y(i))xj(i))+mλθjforj≥1
对应的代码为:
J=-1/m*sum(y.*log(sigmoid(X*theta))+(1.-y).*log(1.-sigmoid(X*theta)))+lambda/(2*m)*(sum(theta.*theta)-theta(1)^2);
grad=1/m*sum((sigmoid(X*theta)-y).*X)+lambda/m*theta';
grad(1)=1/m*sum(sigmoid(X*theta)-y);
这里始终要注意正则化是无需对 θ 0 \theta_0 θ0进行的。对于代价函数,用向量化进行计算时是对全部元素进行操作,但鉴于我们要排除的是第一项,所以我们在求和时减去第一项的平方即可。
2.4 Learning parameters using fminunc
像之前一样,我们可以利用fminunc() 函数来求最优解。但需要补充一正则化参数 λ \lambda λ。
% Initialize fitting parameters
initial_theta = zeros(size(X, 2), 1);
lambda = 1;
% Set Options
options = optimoptions(@fminunc,'Algorithm','Quasi-Newton','GradObj', 'on', 'MaxIter', 1000);
% Optimize
[theta, J, exit_flag] = fminunc(@(t)(costFunctionReg(t, X, y, lambda)), initial_theta, options);
改变
λ
\lambda
λ的值,绘制出相应的图示并进行对比,我们可以观察到:
λ
=
0
\lambda=0
λ=0时,由于特征过多导致过拟合;
λ
=
100
\lambda=100
λ=100时,由于对特征对应的参数惩罚过大,因此使得每个参数值都较小,出现欠拟合的情况。
λ
=
0
:
\lambda=0:
λ=0:
λ
=
1
:
\lambda=1:
λ=1:
λ
=
10
:
\lambda=10:
λ=10:
λ
=
100
:
\lambda=100:
λ=100:
2.5 Evaluation
% Compute accuracy on our training set
p = predict(theta, X);
fprintf('Train Accuracy: %f\n', mean(double(p == y)) * 100);
λ
=
1
\lambda=1
λ=1时: