吴恩达机器学习笔记(3)多类别Logistic回归

这一部分是对吴恩达机器学习多类别logistic回归部分内容的总结,主要分为以下几个部分

1.数据预处理
2.图形绘制
3.多类别Logistic回归

如图所示,当一群数据需要分成多个类别时,所用到的方法就是形成一个伪类,然后逐个判断,说的具体一点,就是比方说判断一个手写数字是0-9的哪一个,那么就建立1或非1,2或非2等等,判断十次,然后选取最大似然值。![在这里插入图片描述](https://img-blog.csdnimg.cn/20191018193014711.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1Nzk4Nzgy,size_16,color_FFFFFF,t_70
在这里插入图片描述让我们逐一分析实现这一过程的代码

1.数据预处理

实际上通过代码我们得知,对图像信息的处理就是将图像转化为一个像素值矩阵,然后将这个矩阵处理为一个很长的一条向量作为一个输入量x_i,将来通过梯度下降算法找到这些长条的共性特点,这一节所涉及的矩阵很多,请读者在疑惑处自行运行代码,找到这些矩阵之间的关系

input_layer_size  = 400;  % 为啥是400呢,因为一条代表20*20的图像拉长
num_labels = 10;          % 0-9,其中010表示
                          % (note that we have mapped "0" to label 10)
load('ex3data1.mat'); % 加载数据
m = size(X, 1);%样本容量
rand_indices = randperm(m);
%randperm函数返回一个随机置换的向量,如果里面只有一个参数,那就是从1到m打乱了返回回来
%其目的是随机显示100个图片放入一个大图片中
sel = X(rand_indices(1:100), :);
%意思是随机取X中的100行,以及每行的所有列信息
displayData(sel);
%这个函数是将上述100张图片显示到一张10*10的大图片中,这个函数的运行方式在后文中介绍                         
2.图形绘制

现介绍plotdata函数的运行方式

function [h, display_array] = displayData(X, example_width)
if ~exist('example_width', 'var') || isempty(example_width) 
	example_width = round(sqrt(size(X, 2)));
end
%上面这一段是定义图片的像素宽度,如果未定义或未赋值图片的像素宽度,则将其定义为一条X的根号那么长
%在本例中就是20*20
colormap(gray);
%设置图窗颜色为灰色
[m n] = size(X);
%这一行代码返回的m是不是总样本容量,而是要展示的样本容量,也就是100个,n是一条数据的长度
example_height = (n / example_width);
%实际上example_height就等于example_width,但是这种计算方式更有普适性,算得高为20
display_rows = floor(sqrt(m));
%所以大图片一行放几个呢?为了好看当然是10*10,于是去根号m的整数
display_cols = ceil(m / display_rows);
%同理这里计算列数,由于为了游刃有余,所以不直接取整而是使用floor和ceil函数
pad = 1;
%这里开始设置画布大小,即背景样式
% Setup blank display
display_array = - ones(pad + display_rows * (example_height + pad), ...
                       pad + display_cols * (example_width + pad));
%按照在图片之间留了一个像素的空隙,这里的灰度图是用[-1,1]的取值,-1为黑1为白,所以背景为白色
%有了背景就可以作画了
curr_ex = 1;%当前图片
for j = 1:display_rows
	for i = 1:display_cols
		if curr_ex > m, 
			break; 
		end
		%画完了就退出来,防止程序出错
		max_val = max(abs(X(curr_ex, :)));
		%这里取最值是为了归一化图像,但是实际上例子中的图片不用归一化也可以
		display_array(pad + (j - 1) * (example_height + pad) + (1:example_height), ...
		              pad + (i - 1) * (example_width + pad) + (1:example_width)) = ...
						reshape(X(curr_ex, :), example_height, example_width) /max_val;
	    %reshape(X,c,r)就是将X拆分为一个r行c列的矩阵,这里用来拆解每一条输入x
	    %注意拆解顺序是按列来的						
		curr_ex = curr_ex + 1;
		%拆解完一个样本后当前样本+1
	end
	if curr_ex > m 
		break; 
	end
	%先进行判断防止错误
end
h = imagesc(display_array, [-1 1]);
%使用imagesc()函数进行可视化,第一个参数是图像矩阵,第二个参数是像素阈值
axis image off
%关闭坐标网格线
drawnow;
%开始绘图
end

有了上述的数据预处理,接下来就可以进行训练了,训练的过程仍然是设置假设函数,设置代价函数,设置梯度,计算最优解,这里仅讨论其代码实现

3.多类别Logistic回归

这里介绍matlab中计算代价函数和梯度的方法
首先定义向量化的西格蒙函数

function g = sigmoid(z)
g = 1.0 ./ (1.0 + exp(-z));
end

然后定义代价函数和梯度的计算函数,这里是有正则化系数的

function [J, grad] = lrCostFunction(theta, X, y, lambda)
m = length(y); % 样本容量
n = size(theta,1);n是theta的个数,注意这里theta是列向量,将来是X*theta
J = (-y'*log(sigmoid(X*theta))-(1-y')*log(1-sigmoid(X*theta)))/m + ...
    lambda/(2.0*m)*(theta(2:n)'*theta(2:n));
%代价函数
grad(1) = X(:,1)'*(sigmoid(X*theta)-y)./m;
grad(2:n) = X(:,2:n)'*(sigmoid(X*theta)-y)./m + ...
lambda/m.*theta(2:n);
%计算梯度,由于正则化的原因,所以第0项要单独计算
grad = grad(:);
%这个代码的意思是把之前的东西变成一个一维列向量
end

有了代价函数和梯度,在主函数中定义正则化系数,然后编辑函数进行θ的计算,代码如下:

lambda = 0.1;%初始化正则化系数
[all_theta] = oneVsAll(X, y, num_labels, lambda);
fprintf('Program paused. Press enter to continue.\n');
pause;

现说明oneVsAll函数的运行方式

function [all_theta] = oneVsAll(X, y, num_labels, lambda)
m = size(X, 1); %样本容量
n = size(X, 2); %每个样本的参数
all_theta = zeros(num_labels, n + 1);%初始化all_theta
%theta的行数为10,代表本实例中0-9的theta,到时候挨个算哪个的概率大就判断为哪个
X = [ones(m, 1) X];%添加x0
for c = 1:num_labels %逐一计算0-9的theta
  initial_theta = zeros(n + 1, 1);
  options = optimset('GradObj', 'on', 'MaxIter', 50);
  %我突然发现之前没有注意,options结构体的设置都是调用optimset函数生成一个结构体
  [theta] = ...
    fmincg (@(t)(lrCostFunction(t, X, (y == c), lambda)), ...
    initial_theta, options);
    %对于大型的,参数很多的矩阵来说,fmincg的效果比fminunc的效果好
    %这里注意,我在y==c这里卡了很久,实际上就是把y=n转换为y=1或y=0
    %这就是OnevsAll的初衷,然后逐个计算每一种情况的theta值
  all_theta(c,:) = theta';
  	%这种theta算出来是个列向量,然后转置储存在all_theta中
end
end

这样就得到了一个10行的theta矩阵,每一样都是theta*X等于该行位置所示的数字的确率(第十行代表数字0)
基于此,我们用得到的theta进行预测
主函数如下:

pred = predictOneVsAll(all_theta, X);

fprintf('\nTraining Set Accuracy: %f\n', mean(double(pred == y)) * 100);
%这一行顺带计算了算法精确度

接下来讨论predictOneVsAll函数的实现:

function p = predictOneVsAll(all_theta, X)
%返回的是一个矩阵p
m = size(X, 1);%样本容量
num_labels = size(all_theta, 1);
p = zeros(size(X, 1), 1);%初始化p,行为测试用例数目,列为1
X = [ones(m, 1) X];%添加x0
temp = all_theta * X';计算每一个x的每一种情况的确率
[maxx, pp] = max(temp);%第二个参数为最大似然数所在的位置,即最终判断值
p = pp';%将该结果返回给p
end

以上就是多类别Logistic回归算法的matlab实现

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值