采用牛顿方法的逻辑回归实现-NG的ML课程exercise5

pre

最近在看NG的ML,看完逻辑回归之后感觉不太理解,所以找了一份网上的练习题练习以加深理解。我找到的练习题应该属于NG在stanford开课时布置的课程作业,网页上有完整的题目描述以及测试数据以及代码,诸位有兴趣可以直接看原题目所在的网页。本篇博客是因为本人在实现逻辑回归时写错了一次,最后标准答案才找到问题,所以这里完整记录方案,以备日后翻阅。

prepare

线性回归

假设可以用一组特征向量X来表示一条测试用例,我们想要建立X与预期输出Y之间的联系。线性回归是这个问题上一个简单而又直观的解决方案,它拥有完备的理论基础,在部分环境下存在很良好的表现。
线性回归假定X与Y之间存在线性关系
Y = θtX
(一般写作 H(X) = θtX )
(这里采用的向量都是列向量)

接下来的问题是如何推导θ
基于我们需要预测的结果尽可能准确,我们可以自然的根据最小平法误差分析定义如下误差公式
J(θ) = ∑( hypothesis - yi)^2
(这个公式用来计算偏差平方和,以此估计预测方法的误差)
出于标准化考虑,我们通常将J(θ)修正为
J(θ) = 1/(2*m) *∑( H(xi)- yi)^2

我们希望得到一个θ,在训练集上,通过线性回归预测的误差最小,所以可以表示为 minθJ(θ)

J(θ)是一个关于θ的n元一次方程组,这是一个凸函数(这边没有证明,我也没有理解),所以可以通过计算σJ(θ)/σθ = 0 来得到极值点,在这个公式中,我们总能得到最小值
最后可以化简到 θ = (XTX)-1XTy
这就是通过标准方程的方式来求得θ的过程

这里不再过分讨论线性回归的其他问题,有兴趣的朋友可以自己另行查找资料

逻辑回归

逻辑回归是在线性回归的基础上添加一层sigmoid函数,来实现将值空间约束到0-1之间,最后用来解决一个二分类的问题(这是个人理解,如果有偏差,请大神不吝赐教)
采用的sigmoid函数为
g(z) = 1/[1 + exp(-z)]

我们采用的预测模型为
H(X) = g(θtX)

我们接下来的问题还是怎么计算θ
如果按照线性回归的方式来定义代价函数J(θ),那么计算会过于复杂,我们这里采用最小平方误差估计的似然函数的方式来表示J(θ), 通过根据y的取值只会是0,1,我们可以得到如下定义
J(θ) = -1/(2*m) *∑( yi*log h(xi) + (1-yi)log(1-h(xi)))

根据不同的方法,利用J(θ)计算θ的方式可能存在差别,但是迭代的格式基本为
θt+1 = θt - Hessian-1δJ(θ)

正规化问题

在我们采用高次方程拟合数据的时候经常出现过拟合的问题(模型在训练集上面表现良好,但是在测试集上偏差很大),假设我们采用的模型如下
y = θ0 + θ1x12x23x3

这种问题通常是由于高次项的系数过大,导致模型的变异过大,我们通常采用在J(θ)中添加高次项的惩罚项,来实现约束效果

Jreg(θ) = J(θ) +λ*∑(θi)^2

问题

数据分布图

我们现在有一个如上图表示的数据集,我们定义采样的特征如下图所示
特征

我们期望采用逻辑回归的方式来构建模型。

题目的详细描述地址斯坦福ML课程exercise5链接

关键代码

function [theta] = NewtomMethod(lambda,x,y)
  [m,n] = size(x);
  %theta = rand(n,1);
  theta = zeros(n,1);

  intialJval = jvalLog(theta,x,y,lambda);

  constMOnes = ones(1,m);
  constDiagMetric = eye(n);
  constDiagMetric(1,1) = 0;

  currentJval = intialJval;
  preJval = currentJval + 1;  % intialize to run algorithm
  while (abs(currentJval - preJval) > 1e-10)
    preJval = currentJval;
    hypo = hypothesisLog(theta,x);
    %calculate deltaJ

    tmp = theta; 
    tmp(1,1) = 0;
    tmp = tmp *(lambda/m);

    deltaJ = (x'*(hypo-y))/m + tmp;

    %calculate H

    H = 0;
    for index = 1:m
      xi = x(index,:);
      H += hypo(index)*(1-hypo(index))*(xi')*xi;
    end
    H = H/m + (lambda/m)*constDiagMetric;
    %H = ((1/m).*x' * diag(hypo) * diag(1-hypo) * x) + (lambda/m)*constDiagMetric;

    %recalculate theta  then update Jvalue
    theta = theta - pinv(H)*deltaJ;

    currentJval = jvalLog(theta,x,y,lambda);
  end
end
function [jVal] = jvalLog(theta,x,y,lambda)
  m = size(x,1);
  hypo = hypothesisLog(theta,x);


  logHypo = log(hypo);
  logNegHypo = log(1-hypo);

  theta(1,1) = 0;
  jVal= (logHypo'*y + logNegHypo'*(1-y))/(-m) + theta'*theta*lambda/(2*m);
end

[λ=1时的划分效果

λ=1时的划分效果

代码托管地址

github仓库

post

我对于octave语法(或者说matlab语法)不太熟悉,所以可能代码有点丑
在计算Hessian时,我采用比较愚蠢的for循环的方式,我注释出来的那行代码是参考答案上的方案,由于公式还没有完全理解,我就没有使用

octave在标量和矩阵/向量运算的时候没有采用特别的符号,所以,需要特别小心之间的混合运算(我在计算Hessian时,将一个n*n矩阵计算成一个标量,由于该项会与一个n*n矩阵进行加法运算,所以最后结果好像正常,这个问题就卡了我好几个小时)

reference

NG的ML公开课
计量经济学(预备知识部分)
the elements of statistical Learning : Data Mining Inference and Prediction

猜你喜欢

转载自blog.csdn.net/u010953266/article/details/78551348