一、逻辑回归的认识
逻辑回归是一个用来解决二分类的简便方法。先来看看逻辑回归解决二分类的基本思想。
之前写了线性回归,现在写逻辑回归~都叫回归,有什么不同呢?
首先,从机器学习的角度说一下。机器学习中,有两个问题是比较相似的,即预测和分类。通常将模型的输出是有限的离散值的问题称为分类问题,而将模型的输出是连续值的问题称为预测。不同的两个问题自然有不同的解决方法,对于预测问题,通常采用回归分析的方法,比如之前线性回归对于输入样本 x
,模型的输出为 y=hθ(x)=θTx ,这里 y的取值是连续性的。
那么回归分析一般是用来做预测的,可不可以用来做分类呢?试想一下,我们用线性回归来解决二分类问题,如果其输出 y
的取值拿一个阈值 τ 卡一下,对于输出 y<τ 的样本分为一类,对于输出 y≥τ 的样本分为另一类,这不就好了么?问题是对于线性回归的输出的取值范围是没有大小边界的,那么这个阈值 τ怎么取就没法弄了。
与线性回归不同,逻辑回归输出的取值范围是0到1之间,这样的话,选一个阈值 τ
似乎比较可行了,为了说明怎么选,先看看逻辑函数(也叫sigmod函数)长啥样吧~逻辑函数的定义是这样的 g(z)=11+e−z , z∈R1 , g(z)∈(0,1)。它的图形长这样:
现在可以看出我们选的阈值应当是0.5,因为从图形上看,函数值取0.5时对应的自变量取值为0,而整个曲线是关于(0,0.5)中心对称的,这意味这选这个点对两类样本而言是比较公平的(可以这么理解吧~)。也就是说,逻辑函数可以将输入分为两类,第一类 z>0
, g(z)>0.5 ,而第二类 z<0 , g(z)<0.5。
一般情况下,我们的输入 x
是多维的啊,而逻辑函数的输入是个标量,所以用逻辑函数对我们的多维样本分类首先要对样本进行一个变换 z=θTx (注意对样本加入常数项截距,即 z=θ1(x1=1)+θ2x2+...+θn−1xn−1+θnxn ,对原来n-1为输入增加取值为1的一维,只是为了方便写成向量形式),变换后的逻辑函数可以写出:
那么现在要对样本分成两类了: θTx>0,hθ(x)>0.5
的一类和 θTx<0,hθ(x)<0.5 的一类,而逻辑回归的任务就是根据已有的带类别的样本找到这个 θ。(后面第三部分结合似然函数再来分析这个结果)。
二、逻辑回归求解
逻辑回归的基本模型已经有了 hθ(x)=g(θTx)=11+e−θTx
,那么怎么求解呢?好像没说解什么呢^_^,当然是解参数 θ 了,我们要找个 θ使得我们的模型是最优的嘛,参数估计问题~所以,先写出对数似然函数吧!
ℓ(θ)=log∏i=1mp(y(i)|x(i);θ)
,其中m是样本数目,i是样本编号。感觉怪怪的,突然冒出一个 y(i) 来,而且 p(y(i)|xi,θ) 也不知道啊。。。 y(i) 是啥呢,当然是样本类别了,我们不是要分类吗,每个样本本身当然有个类别了,这里是二分类就取0或者1吧。接着来看 p(y(i)|xi,θ) ,没法求吧,因为我们还没对 y(i)|xi,θ 建模啊,模型都没有,概率当然求不了。 y(i) 的取值只有0和1两个,所以它应当是一个伯努利分布,我们需要确定分别取这两个值的概率。回顾一下上面的 hθ(x) ,其取值范围为(0,1),这不正好嘛, y(i) 取值的概率本身就是0和1之间的么!好了,干脆直接让 p(y=1|x,θ)=hθ(x) , p(y=0|x,θ)=1−hθ(x) 得了,这正好符合概率的定义的。那这样做有什么意义呢?回顾上面的内容,当 hθ(x) 小于0.5时,我们将样本分类为类别0,否则分类为类别1,这样的话取值范围为(0,1)的 hθ(x) 是不是可以衡量样本属于类别1的概率呢?结合逻辑回归函数的曲线看, z=θTx 比0大的越多, hθ(x) 取值越是偏离阈值0.5而离1越近,这意味这这个样本的分类越不模糊,很明确的属于其中一个类,相反 hθ(x) 取值越是偏离阈值0.5而离0越近,样本越是很明确的属于另一个类别。这样的话,样本归为类别1的概率就是 hθ(x) ,归类为类别0的概率就是 1−hθ(x) 。好了, y(i)|xi,θ的模型好了,即:
p(y(i)=1|x(i),θ)=hθ(x(i))
, p(y(i)=0|x(i),θ)=1−hθ(x(i))
将他俩写出一个式子
p(y(i)|x(i),θ)=(hθ(x(i)))y(i)(1−hθ(x(i)))1−y(i)
现在,可以接着写似然函数了
ℓ(θ)=log∏i=1mp(y(i)|x(i);θ)=∑i=1mlog((hθ(x(i)))y(i)(1−hθ(x(i)))1−y(i))=∑i=1m(y(i)log(hθ(x(i)))+(1−y(i))log((1−hθ(x(i)))))(1)(2)(3)
之前提到有人认为可以简单理解为逻辑回归是对线性回归的结果做了一个逻辑函数的转换,然后用来做二分类,现在有了似然函数就可以理解这种说法不准确了,因为两者求解的目标是不一样的,在逻辑回归的似然函数中,不存在线性回归中优化最小二乘的目标。
现在优化这个似然函数使其取最大值就可以了。
对 θ
的第 l 个分量 θl 求偏导(注意 hθ(x(i))=g(θTx(i)) 且利用逻辑函数求导结果 g(z)′=g(z)(1−g(z)))
∂ℓ(θ)∂θl=∂∑i=1m(y(i)log(hθ(x(i)))+(1−y(i))log((1−hθ(x(i)))))∂θl=∑i=1m(y(i)1hθ(x(i))+(1−y(i))11−hθ(x(i)))∂hθ(x(i))∂θl=∑i=1m(y(i)1hθ(x(i))−(1−y(i))11−hθ(x(i)))∂g(θTx(i))∂θl=∑i=1m(y(i)1hθ(x(i))−(1−y(i))11−hθ(x(i)))g(θTx(i))(1−g(θTx(i)))∂θTx(i)∂θl=∑i=1m(y(i)(1−g(θTx(i))−(1−y(i))g(θTx(i)))x(i)l=∑i=1m(y(i)−g(θTx(i)))x(i)l(4)(5)(6)(7)(8)(9)
要得到解析解,可以令偏导为0,解一下 θl
,不过解一下就会发现上面的式子不好解。所以为了求解参数 θ,用最优化的方法吧~牛顿法,梯度法之类的。
另外一个问题,这个似然函数能不能求最大值呢?也就是说它万一是个凸函数,就可能有最小值而没最大值了,所以我们需要证明个个函数是个凹函数,这样利用优化方法找到一个局部极大值就是全局最大值了,好了,来证其Hessien矩阵半负定吧~
利用上面对 θl
的求导结果,Hessian矩阵第 k 行第 l列的元素
Hkl=∂2ℓ(θ)∂k∂l=∂∑i=1m(y(i)−g(θTx(i)))x(i)l∂θk=∑i=1m−g(θTx(i))(1−g(θTx(i)))x(i)kx(i)l(10)(11)(12)
那么 H=∑i=1m−g(θTx(i))(1−g(θTx(i)))x(i)x(i)T
对于任意非零向量 p
有
pTHp=∑i=1m−g(θTx(i))(1−g(θTx(i)))pTx(i)x(i)Tp=−∑i=1mg(θTx(i))(1−g(θTx(i)))(pTx(i))2(13)(14)
由于 0<g(θTx(i))<1
,所以 pTHp≤0,所以似然函数的Hessien矩阵半负定,它是一个凹函数,这样,利用最优化方法求一个局部极大值就可以了。
三、逻辑回归干了干啥
上面推导了逻辑回归的求解的过程,乱乱的,简单总结一下逻辑回归干了个啥吧~
回顾似然函数 ℓ(θ)=log∏i=1mp(y(i)|xi,θ)
,我们的目标要最大化这个东西,也就是要最大化连乘符号里面的每一项 p(y(i)|x(i),θ)=(hθ(x(i)))y(i)(1−hθ(x(i)))1−y(i) ,它怎么才能大呢?考虑单个样本 x 如果它对应类别 y=1 ,那么 p(y|x,θ)=hθ(x) ,所以 hθ(x) 要比较大才好,而 hθ(x)=g(θTx)=11+e−θTx ,所以 θTx 要大于0比较好(结合逻辑函数曲线看看);相反如果 y=0 ,最大化似然函数则要求 θTx尽可能小于零。
所以最大化似然函数的解就是找到一个 θ
,是得对于类别为1的样本,尽可能满足 θTx>0 ,而对于类别为0的样本,尽可能满足 θTx<0 。换句话说,我们找到的超平面 θTx=0用来对样本分类。可以看出,现在从似然函数分析的结果和我们之前第一部分末尾提出的逻辑回归的目标是一致的。
四、简单实现
#l逻辑函数
logistic<-function(x){
return(1/(1+exp(-x[1])));
}
#似然函数
ll<-function(theta,x,y){
n=ncol(x);
m=nrow(x);
l<-0;
for(i in seq(1,m)){
xi<-matrix(x[i,],ncol=1);
hxi<-logistic(t(xi)%*%theta);
l<-l+y[i]*log(hxi)+(1-y[i])*log((1-hxi))
}
return(-l) #取负值为了使用下面的nlm()函数
}
#读入数据,数据来自Andrew Ng机器学习资料
x<-read.table("q1x.txt");
x<-as.matrix(x);
x<-cbind(rep(1,99),x);
y<-scan("q1y.txt");
y<-matrix(y,ncol=1);
n=ncol(x);
m=nrow(x);
theta<-rep(0,n);
theta<-matrix(theta,ncol=1);
result<-nlm(ll,theta,x,y);#nlm()为R运用牛顿法求解函数极小值的函数
est<-result$estimate;
plot(x[1:50,2:3],type="p",col="red",xlim=c(0,8), ylim=c(-4,3));
points(x[51:99,2:3],type="p",col="blue");
abline(-est[1]/est[3],-est[2]/est[3]);