分类
分类应是极为常见的问题,我们生活周边的一切事物,皆是类别分明。机器学习领域,处理分类问题的方法有多种,如逻辑回归、支持向量机、以及无监督学习的K-mean等等。本文主要介始逻辑回归。
逻辑回归
逻辑回归,主要用于解决分类问题,例如二分类。
对于二分类问题,通过给出的样本((x,y))(若为二分类,y={0,1}),确定一个可以对数据一分为二的边界,有了这个边界,对于一个新的样本,根据其特征,便能预测其类属。边界可以是一根直线,或是一个圆,或是一个多边形等。
对于多分类问题,可以通过执行多次二分类解决:保留要区分的一类,剩下的归为另一类。例如,区分A、B、C类,需执行如下三次二分类:
首先,保留A类,将B和C归为other,执行二分类,区分出A类。
接着,保留B类,将A和C归为other,执行二分类,区分出B类。
同样,保留C类,将A和B归为other,执行二分类,区分出C类。
分类问题的解决方法,与线性回归类似,一样从误差函数入手,一样使用梯度下降法。
原理
分类问题,其 (y) 值一般设置为有限的离散值,例如0、1。所以系统所要做的工作,就是当一个新的样本输入时,需要判断其为可能值的概率分别有多大,以此在确定其y值,即其类属。
1、模型假设
令逻辑回归的假设函数为:(h_ heta(x) = g( heta^Tx))
其中,(g(z) = frac{1}{1+e^{-z}}),为sigmoid函数。
对g(z)函数的理解
g(z)函数是来源于最大熵原理,通过拉格朗日乘数法(寻找变量受一个或多个条件限制的多元函数极值的方法)求偏导得出,故而 (h_ heta(x))的值,其实是系统 "认为" 样本为 "1" 的概率值P,即:
( h_ heta(x) = P(y=1|x) )
使用 sigmoid 函数的优点
以二分类为例,根据输入样本的特征,确定其输出为 0 或 1,显然阶跌函数有这些特性,如下
可以看到,阶跃函数在 (t_0) 处有两个问题:
(1) (t_0) 时的值应当认为 0 还是 1?
(2) (t_0) 发生了跃变,数学上求导麻烦。
而sigmoid函数,其值满足0~1之间,且为单调递增的连续曲线,比之阶跃函数更有优势。
2、误差函数
误差函数为
( J = frac{1}{m} sum_{i=1}^{m}[-y^{(i)}log(h_ heta(x^{(i)})) - (1-y^{(i)})log(1-h_ heta(x^{(i)}))] )
误差函数对 ( heta) 的导数为
( grad = frac{1}{m}sum_{i=1}^{m}(h_ heta(x^{(i)})-y^{(i)})x_j^{(i)} )
一、最简单的二分类,一阶特征,直线边界
1、误差函数及偏导数
1.1 误差函数实现
function [J, grad] = costFunction(theta, X, y)
m = length(y); % number of training examples
J = 0;
grad = zeros(size(theta));
h = sigmoid(X*theta);
J = ((-y' * log(h)) - (1-y)' * log(1-h))/m;
grad = 1/m .* X' * (h-y);
% =============================================================
end
1.2 误差函数测试
[m, n] = size(X);
% Add intercept term to x and X_test
X = [ones(m, 1) X];
% Initialize fitting parameters
initial_theta = zeros(n + 1, 1);
% Compute and display initial cost and gradient
[cost, grad] = costFunction(initial_theta, X, y);
fprintf('Cost at initial theta (zeros): %f
', cost);
fprintf('Expected cost (approx): 0.693
');
fprintf('Gradient at initial theta (zeros):
');
fprintf(' %f
', grad);
fprintf('Expected gradients (approx):
-0.1000
-12.0092
-11.2628
');
% Compute and display cost and gradient with non-zero theta
test_theta = [-24; 0.2; 0.2];
[cost, grad] = costFunction(test_theta, X, y);
fprintf('
Cost at test theta: %f
', cost);
fprintf('Expected cost (approx): 0.218
');
fprintf('Gradient at test theta:
');
fprintf(' %f
', grad);
fprintf('Expected gradients (approx):
0.043
2.566
2.647
');
2、梯度下降算法
这里使用优化的函数进行
% Set options for fminunc
options = optimset('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 to screen
fprintf('Cost at theta found by fminunc: %f
', cost);
fprintf('Expected cost (approx): 0.203
');
fprintf('theta:
');
fprintf(' %f
', theta);
fprintf('Expected theta (approx):
');
fprintf(' -25.161
0.206
0.201
');
3、预测
prob = sigmoid([1 45 85] * theta);
fprintf(['For a student with scores 45 and 85, we predict an admission ' ...
'probability of %f
'], prob);
fprintf('Expected value: 0.775 +/- 0.002
');
% Compute accuracy on our training set
p = predict(theta, X);
fprintf('Train Accuracy: %f
', mean(double(p == y)) * 100);
fprintf('Expected accuracy (approx): 89.0
');
二、多边形边界
上面是最简单的分类问题,而现实中的样本,往往需要拟合一条曲线来划分数据,即是多项式拟合。
其处理方法,基本与上式相同。不同的是需要将特征转为多项式转换,使之能拟合更复杂的边界,如圆、或者其他的不规则图形。
1、数据预处理,生成多项式特征
X = mapFeature(X(:,1), X(:,2));
生成多项式的方法如下:
function out = mapFeature(X1, X2)
degree = 6;
out = ones(size(X1(:,1)));
for i = 1:degree
for j = 0:i
out(:, end+1) = (X1.^(i-j)).*(X2.^j);
end
end
end
2、训练
使用与一阶边界相同的方法
% Initialize fitting parameters
initial_theta = zeros(size(X, 2), 1);
% Set Options
options = optimset('GradObj', 'on', 'MaxIter', 400);
% Optimize
[theta, J, exit_flag] = ...
fminunc(@(t)(costFunction(t, X, y)), initial_theta, options);
3、预测
二分类的预测方法:对于一个新的样本,分别计算其为0、1概率,取大于0.5的值做为输出。
p = predict(theta, X);
fprintf('Train Accuracy: %f
', mean(double(p == y)) * 100);
function p = predict(theta, X)
m = size(X, 1); % Number of training examples
p = zeros(m, 1);
p_medium = sigmoid(X*theta);
pos = find(p_medium >= 0.5);
p(pos,1)=1;
end
三、多分类问题
例如给出如下训练集,100张大小为20*20图,内容为0~9的数字
X 为每张图的像素数值,即特征数 n = 400
y 为图上的数字,即y = {0,1,2,3,4,5,6,7,8,9}
1、训练
[all_theta] = oneVsAll(X, y, num_labels);
分别对每个数字进行训练,得出10个theta矩阵。
function [all_theta] = oneVsAll(X, y, num_labels)
m = size(X, 1);
n = size(X, 2);
all_theta = zeros(num_labels, n + 1);
% Add ones to the X data matrix
X = [ones(m, 1) X];
initial_thata = zeros(n+1,1);
options = optimset('GradObj','on','MaxIter',50);
for c = 1:num_labels
[all_theta(c,:)] = fmincg(@(t)(costFunction(t,X,(y ==c))),initial_thata,options);
end
end
2、预测
输入一张图片,计算其为0~9的各个概率,概率最大的值就是其输出。
pred = predictOneVsAll(all_theta, X);
fprintf('
Training Set Accuracy: %f
', mean(double(pred == y)) * 100);
function p = predictOneVsAll(all_theta, X)
m = size(X, 1);
num_labels = size(all_theta, 1);
p = zeros(size(X, 1), 1);
X = [ones(m, 1) X];
% 计算得出X中,可能的所有概率值,取最大
h = sigmoid(X* all_theta');
[~,p] = max(h,[],2);
end