假设现在有一些数据点,我们用一条直线对这些点进行拟合(该直线称为最佳拟合直线),这个拟合的过程就称为回归。
利用Logistic(逻辑斯蒂)回归是一个分类模型而不回归模型。其进行分类的主要思想是:根据现有数据对分类边界线建立回归公式,以此进行分类。这里的“回归”一词源于最佳拟合,表示要找到最佳拟合参数。而最佳拟合参数就是在训练分类器时,通过最优化算法获得。
首先,逻辑斯蒂回归是一种线性分类器,针对的是线性可分问题!
先看两个函数logit和sigmoid函数.
几率比:指特定事件发生的几率。如下式所示。其中p为事件1发生的概率: p 1 − p \frac{p}{1-p} 1−pp.
进一步地,我们可以logit函数,为几率比的对数函数 l o g i t ( p ) = l o g p 1 − p logit(p)=log\frac{p}{1-p} logit(p)=log1−pp,在logistic回归中, q = p ( y = 1 ∣ x ) q=p(y=1|x) q=p(y=1∣x).
而对于某一样本属于特定类别的概率,为logit函数的反函数,称为logistic函数,由于它的图像呈S形,有时也称为sigmoid函数: π ( z ) = 1 1 + e − z \pi(z)=\frac{1}{1+e^{-z}} π(z)=1+e−z1,在logistic回归中, z = w T x + b = w 1 x 1 + w 2 x 2 + ⋯ + w n x n + b z=w^Tx+b=w_1x_1+w_2x_2+\cdots+w_nx_n+b z=wTx+b=w1x1+w2x2+⋯+wnxn+b,这里要知道 π ′ ( z ) = π ( z ) ( 1 − π ( z ) ) \pi^{'}(z)=\pi(z)(1-\pi(z)) π′(z)=π(z)(1−π(z)).
1 Logistic回归模型
下面正式地来讲Logistic回归模型。
考虑具有个独立变量的向量 x = ( x 1 , x 2 , ⋯   , x n ) , x=(x_1,x_2,\cdots,x_n), x=(x1,x2,⋯,xn),,设条件慨率 p ( y = 1 ∣ x ) = p p(y=1|x)=p p(y=1∣x)=p为根据观测量相对于某事件x发生的概率.
那么Logistic回归模型可以表示为 p ( y = 1 ∣ x ) = π ( z ) = 1 1 + e − ( w T x + b ) p(y=1|x)=\pi(z)=\frac{1}{1+e^{-(w^Tx+b)}} p(y=1∣x)=π(z)=1+e−(wTx+b)1,
其中, z = w T x + b = w 1 x 1 + w 2 x 2 + ⋯ + w n x n + b z=w^Tx+b=w_1x_1+w_2x_2+\cdots +w_nx_n+b z=wTx+b=w1x1+w2x2+⋯+wnxn+b.
那么在x条件下y不发生的概率为
p ( y = 0 ∣ x ) = 1 − p ( y = 1 ∣ x ) = 1 − 1 1 + e − ( w T x + b ) = e − ( w T x + b ) 1 + e − ( w T x + b ) p(y=0|x)=1-p(y=1|x)=1-\frac{1}{1+e^{-(w^Tx+b)}}=\frac{e^{-(w^Tx+b)}}{1+e^{-(w^Tx+b)}} p(y=0∣x)=1−p(y=1∣x)=1−1+e−(wTx+b)1=1+e−(wTx+b)e−(wTx+b).
所以事件发生与不发生的概率之比为 p ( y = 1 ∣ x ) p ( y = 0 ∣ x ) = p 1 − p = e w T x + b \frac{p(y=1|x)}{p(y=0|x)}=\frac{p}{1-p}=e^{w^Tx+b} p(y=0∣x)p(y=1∣x)=1−pp=ewTx+b,这个比值称为事件的发生比(the odds of experiencing an event),简记为odds。
对odds取对数得到 ln ( p 1 − p ) = w x + b \ln(\frac{p}{1-p})=wx+b ln(1−pp)=wx+b.
先给出求解参数w的思路,下面我们便按照这个思路进行求解参数w:
1、为求解参数w,我们需要定义一个准则函数 J(w),利用准则函数求解参数w.
2、我们通过最大似然估计法定义准则函数J(w).
3、接下来通过最大化准则函数J(w)便可求出参数w的迭代表达式.
4、为了更好地使用数据求出参数w,我们将第三步得到的w的迭代时向量化。
步骤一、求解准则函数J(w).
先将上面p(y|x)的两个式子合并: p ( y ∣ x , w ) = ( π ( z ) ) y ( 1 − π ( z ) ) 1 − y p(y|x,w)=(\pi(z))^{y}(1-\pi(z))^{1-y} p(y∣x,w)=(π(z))y(1−π(z))1−y.
上式是个二分类问题,所以y只是取两个值0或是1。
设有m组样本如下:
( x 1 ( 1 ) , x 2 ( 1 ) , ⋯   , x n ( 1 ) ) , ( x 1 ( 2 ) , x 2 ( 2 ) , ⋯   , x n ( 2 ) ) , ⋯   , ( x 1 ( m ) , x 2 ( m ) , ⋯   , x n ( m ) ) (x_1^{(1)},x_2^{(1)},\cdots,x_n^{(1)}),(x_1^{(2)},x_2^{(2)},\cdots,x_n^{(2)}),\cdots,(x_1^{(m)},x_2^{(m)},\cdots,x_n^{(m)}) (x1(1),x2(1),⋯,xn(1)),(x1(2),x2(2),⋯,xn(2)),⋯,(x1(m),x2(m),⋯,xn(m)),
因为各个观测样本之间相互独立,那么它们的联合分布为各边缘分布的乘积,得到似然函数为
L ( w ) = ∏ i = 1 m ( π ( z ( i ) ) ) y ( i ) ( 1 − π ( z ( i ) ) ) 1 − y ( i ) L(w)=\prod\limits_{i=1}^m(\pi(z^{(i)}))^{y^{(i)}}(1-\pi(z^{(i)}))^{1-y^{(i)}} L(w)=i=1∏m(π(z(i)))y(i)(1−π(z(i)))1−y(i),其中 z ( i ) = w 0 + w 1 x 1 ( i ) + w 2 x 2 ( i ) + ⋯ + w n x n ( i ) z^{(i)}=w_0+w_1 x_1^{(i)}+w_2 x_2^{(i)}+\cdots+w_nx_n^{(i)} z(i)=w0+w1x1(i)+w2x2(i)+⋯+wnxn(i).
然后我们的目标是求出使这一似然函数的值最大的参数估计,最大似然估计就是求出参数w,b,使得L(w)取得最大值,对函数L(w)取对数得到
J ( w ) = 1 m ln L ( w ) = 1 m ∑ i = 1 m ( y ( i ) ln ( π ( z ( i ) ) ) + ( 1 − y ( i ) ) ln ( 1 − π ( z ( i ) ) ) ) J(w)=\frac{1}{m}\ln L(w)=\frac{1}{m}\sum\limits_{i=1}^m(y^{(i)}\ln(\pi(z^{(i)}))+(1-y^{(i)})\ln(1-\pi(z^{(i)}))) J(w)=m1lnL(w)=m1i=1∑m(y(i)ln(π(z(i)))+(1−y(i))ln(1−π(z(i)))).
现在开始L(w)分别对 w 1 , w 2 , ⋯   , w n w_1,w_2,\cdots,w_n w1,w2,⋯,wn求偏导,下面只计算对 w j w_j wj的偏导.
∂ ∂ w j ln L ( w ) = ∑ i = 1 m ( y ( i ) 1 π ( z ( i ) ) − ( 1 − y ( i ) ) 1 1 − π ( z ( i ) ) ) ∂ ∂ w j π ( z ( i ) ) \frac{\partial}{\partial w_j}\ln L(w)=\sum\limits_{i=1}^m(y^{(i)}\frac{1}{\pi(z^{(i)})}-(1-y^{(i)})\frac{1}{1-\pi(z^{(i)})})\frac{\partial}{\partial w_j}\pi(z^{(i)}) ∂wj∂lnL(w)=i=1∑m(y(i)π(z(i))1−(1−y(i))1−π(z(i))1)∂wj∂π(z(i)),
其中, 1 ∂ w j π ( z ( i ) ) = ∂ π ( z ( i ) ) ∂ z ( i ) ∂ z ( i ) ∂ w j \frac{1}{\partial w_j}\pi(z^{(i)})=\frac{\partial \pi(z^{(i)})}{\partial z^{(i)}}\frac{\partial z^{(i)}}{\partial w_j} ∂wj1π(z(i))=∂z(i)∂π(z(i))∂wj∂z(i).
由sigmoid函数的导数公式得 π ′ ( z ( i ) ) = π ( z ( i ) ) ( 1 − π ( z ( i ) ) ) \pi^{'}(z^{(i)})=\pi(z^{(i)})(1-\pi(z^{(i)})) π′(z(i))=π(z(i))(1−π(z(i))),从而, 1 ∂ w j π ( z ( i ) ) = π ( z ( i ) ) ( 1 − π ( z ( i ) ) ) x j \frac{1}{\partial w_j}\pi(z^{(i)})=\pi(z^{(i)})(1-\pi(z^{(i)}))x_j ∂wj1π(z(i))=π(z(i))(1−π(z(i)))xj,带入上式得,
∂ ∂ w j ln L ( w ) = ∑ i = 1 m ( y i 1 π ( z ( i ) ) − ( 1 − y i ) 1 1 − π ( z ( i ) ) ) π ( z ( i ) ) ( 1 − π ( z ( i ) ) ) x j ( i ) = ∑ i = 1 m ( y i − π ( z ( i ) ) ) x j ( i ) \frac{\partial}{\partial w_j}\ln L(w)=\sum\limits_{i=1}^m(y_i\frac{1}{\pi(z^{(i)})}-(1-y_i)\frac{1}{1-\pi(z^{(i)})})\pi(z^{(i)})(1-\pi(z^{(i)}))x_j^{(i)}=\sum\limits_{i=1}^m(y_i-\pi(z^{(i)}))x_j^{(i)} ∂wj∂lnL(w)=i=1∑m(yiπ(z(i))1−(1−yi)1−π(z(i))1)π(z(i))(1−π(z(i)))xj(i)=i=1∑m(yi−π(z(i)))xj(i).
步骤二 梯度下降算法求解参数w.
这里我们使用梯度下降算法求解参数w,因此参数w的迭代式为:
w : = w + Δ w , Δ W = − α ∇ J ( w ) w:=w+\Delta w,\Delta W=-\alpha\nabla J(w) w:=w+Δw,ΔW=−α∇J(w),这里w是一个n行1列的向量, w = ( w 0 , w 1 , ⋯   , w n ) T w=(w_0,w_1,\cdots,w_n)^T w=(w0,w1,⋯,wn)T,
w
j
w_j
wj的更新公式如下:
w
j
:
=
w
j
+
Δ
w
j
,
Δ
w
j
=
−
α
∂
J
(
w
)
∂
w
j
w_j:=w_j+\Delta w_j, \Delta w_j=-\alpha\frac{\partial J(w)}{\partial w_j}
wj:=wj+Δwj,Δwj=−α∂wj∂J(w),
其中,
∂
J
(
w
)
w
j
=
∑
i
=
1
m
(
y
i
−
π
(
z
(
i
)
)
)
x
j
(
i
)
\frac{\partial J(w)}{w_j}=\sum\limits_{i=1}^m(y_i-\pi(z^{(i)}))x_j^{(i)}
wj∂J(w)=i=1∑m(yi−π(z(i)))xj(i).
因此,更新权重的公式如下:
w j : = w j − α ∑ i = 1 m ( y j − π ( z ) ) x j , j = 0 , 1 , 2 , ⋯   , n w_j:=w_j-\alpha \sum\limits_{i=1}^m(y_j-\pi(z))x_j,\ j=0,1,2,\cdots,n wj:=wj−αi=1∑m(yj−π(z))xj, j=0,1,2,⋯,n.
矩阵版本的更新公式为:
w : = w − α ∇ J ( w ) = w − α X T E w:=w-\alpha \nabla J(w)=w-\alpha X^TE w:=w−α∇J(w)=w−αXTE,这里X和E的值如下所示:
$
X=\begin{bmatrix}
1 & x_1^{(1)} & x_2^{(1)} & \cdots & x_n^{(1)} \
1 & x_1^{(2)} & x_2^{(2)} & \cdots & x_n^{(2)} \
\vdots & \vdots & \vdots & \ddots & \vdots \
1 & x_1^{(m)} & x_2^{(m)} & \cdots & x_n^{(m)}
\end{bmatrix}
$,
y
=
[
y
(
1
)
y
(
2
)
⋮
y
(
m
)
]
y=\begin{bmatrix} y^{(1)}\\y^{(2)}\\ \vdots \\ y^{(m)} \end{bmatrix}
y=⎣⎢⎢⎢⎡y(1)y(2)⋮y(m)⎦⎥⎥⎥⎤
$,
w=\begin{bmatrix}
w_0 \ w_1 \ w_2 \ \vdots \ w_n
\end{bmatrix}
$,
E
=
y
−
s
i
g
m
o
i
d
(
X
∗
w
)
E=y-sigmoid(X*w)
E=y−sigmoid(X∗w).
步骤三 梯度上升算法的伪代码如下:
每个回归系数初始化为1
重复R次:
\qquad
计算整个数据集的梯度
\qquad
使用
η
×
g
r
a
d
i
e
n
t
\eta\times gradient
η×gradient更新回归系数的向量
返回回归系数
代码如下:
def sigmoid(x):
return 1.0/(1+np.exp(-x))
def gradAscent(data,classLabels):
"""
Input:
m,n=data.shape
data的第一列是全1,即将w_0+w_1*x_1+w_2*x_2+...+w_{n-1}*x_{n-1}写作w_0*x_0+w_1*x_1+w_2*x_2+...+w_{n-1}*x_{n-1},其中x_0=1
m表示样本数,比如100组样本
n表示变量的个数,即x_0,x_1,x_{n-1},其中x_0恒等于1
classLabels为m行1列
Output:
weights为n行1列,其中w_0为常数项,w_i为x_i的系数
"""
data=np.matrix(data)
labelMat=np.matrix(classLabels)
m,n=data.shape
alpha=0.001
maxCycles=500
weights=np.asmatrix(np.ones((n,1)))
for k in range(maxCycles):
h=sigmoid(data*weights)
error=labelMat-h
weights=weights+alpha*data.T*error
return weights
加载数据,运行函数如下:
import pdb
#pdb.set_trace()
import pandas as pd
dataset=pd.read_csv('d:/testSet.txt',sep='\t',header=None)
labels_pd=dataset.loc[:,2]
labels=np.matrix(labels_pd).T
data_pd=dataset.loc[:,0:1]
data=pd.concat([pd.DataFrame(np.ones(100)),data_pd],axis=1)
w=gradAscent(data,labels)
#结果如下:
matrix([[ 4.12414349],
[ 0.48007329],
[-0.6168482 ]])
2 分析结果
def plotBestFit(data,labels,weights):
import matplotlib.pyplot as plt
import numpy as np
data=np.matrix(data)
labels=np.matrix(labels)
m,n=data.shape
x1=[];x2=[];y1=[];y2=[]
for i in range(m):
if int(labels[i,0])==1:
x1.append(data[i,1]);y1.append(data[i,2])
else:
x2.append(data[i,1]);y2.append(data[i,2])
fig=plt.figure()
ax=fig.add_subplot(111)
ax.scatter(x1,y1,s=30,c='red',marker='s')
ax.scatter(x2,y2,s=30,c='green')
x=np.arange(-3.0,3.0,0.1)
y=(-weights[0,0]-weights[1,0]*x)/weights[2,0]
ax.plot(x,y)
plt.xlabel('x1');plt.ylabel('x2')
plt.show()
plotBestFit(data,labels,w)
结果如下:
3 随机梯度上升
梯度上升算法在每次更新回归系数时都需要遍历整个数据集,该方法在处理小数据时还尚可,但如果有数十亿样本和成千上万的特征,那么该方法的计算复杂度太高了,改进方法便是一次仅用一个数据点来更新回归系数,此方法便称为随机梯度上升算法!由于可以在更新样本到来时对分类器进行增量式更新,因而随机梯度上升算法是一个“在线学习算法”。而梯度上升算法便是“批处理算法”!
3.1 代码和结果
def stocGradAscent(data,classLabels):
data=np.array(data)
labelMat=np.array(classLabels)
m,n=data.shape
alpha=0.01
weights=np.ones(n,)
for i in range(m):
h=sigmoid(sum(data[i]*weights))
error=labelMat[i,0]-h
weights=weights+alpha*data[i]*error
return weights
导入数据并画图如下:
import pandas as pd
dataset=pd.read_csv('d:/testSet.txt',sep='\t',header=None)
labels_pd=dataset.loc[:,2]
labels=np.matrix(labels_pd).T
data_pd=dataset.loc[:,0:1]
data=pd.concat([pd.DataFrame(np.ones(100)),data_pd],axis=1)
w=stocGradAscent(data,labels)
w=np.matrix(w).T
plotBestFit(data,labels,w)
可以看到,分类器错分了大概三分之一的样本.
3.2 结果分析
将stocGradAscent修改一下,将上面的代码执行num次,保存每次迭代时的weights的值,最后做出weights的三个量随迭代次数的变化曲线图.
def stocGradAscent(data,classLabels):
data=np.array(data)
labelMat=np.array(classLabels)
m,n=data.shape
alpha=0.5
weights=np.ones(n,)
num=200
weights_list=[]
for j in range(num):
for i in range(m):
h=sigmoid(sum(data[i]*weights))
error=labelMat[i,0]-h
weights=weights+alpha*data[i]*error
weights_list.append(list(weights))
return weights,weights_list
加载数据,运行程序:
import pandas as pd
dataset=pd.read_csv('d:/testSet.txt',sep='\t',header=None)
labels_pd=dataset.loc[:,2]
labels=np.matrix(labels_pd).T
data_pd=dataset.loc[:,0:1]
data=pd.concat([pd.DataFrame(np.ones(100)),data_pd],axis=1)
w,w_list=stocGradAscent(data,labels)
最后,画出weights的三个量随迭代次数的变化曲线图如下:
import matplotlib.pyplot as plt
w_list_mat=np.array(w_list)
fig=plt.figure()
ax1=fig.add_subplot(311)
ax1.plot(w_list_mat[:,0])
plt.ylabel('x0')
ax2=fig.add_subplot(312)
ax2.plot(w_list_mat[:,1])
plt.ylabel('x1')
ax3=fig.add_subplot(313)
ax3.plot(w_list_mat[:,2])
plt.ylabel('x2')
plt.show()
可以看出,回归系数经过大量迭代才能达到稳定值,并且仍然有局部的波动现象.
3.3 改进的随机梯度上升算法
随机梯度上升算法虽然大大减少了计算复杂度,但是同时正确率也下降了!所以可以对随机梯度上升算法进行改进!改进分为两个方面:
改进一:对于学习率alpha采用非线性下降的方式使得每次都不一样.
改进二:每次使用一个数据,但是每次随机的选取数据,选过的不在进行选择.
def stocGradAscent1(data,classLabels,numIter=200):
data=np.array(data)
labelMat=np.array(classLabels)
m,n=data.shape
alpha=0.5
weights=np.ones(n,)
weights_list=[]
for j in range(numIter):
dataIndex = list(range(m))
for i in range(m):
alpha=4/(1.0+j+i)+0.01
randIndex = int(np.random.uniform(0,len(dataIndex)))
h=sigmoid(sum(data[randIndex]*weights))
error=labelMat[randIndex,0]-h
weights=weights+alpha*data[randIndex]*error
del(dataIndex[randIndex])
weights_list.append(list(weights))
return weights,weights_list
import pandas as pd
dataset=pd.read_csv('d:/testSet.txt',sep='\t',header=None)
labels_pd=dataset.loc[:,2]
labels=np.matrix(labels_pd).T
data_pd=dataset.loc[:,0:1]
data=pd.concat([pd.DataFrame(np.ones(100)),data_pd],axis=1)
w,w_list=stocGradAscent1(data,labels)
w=np.matrix(w).T
plotBestFit(data,labels,w)
画出weights的三个值随迭代次数的变化曲线图如下:
import matplotlib.pyplot as plt
w_list_mat=np.array(w_list)
fig=plt.figure()
ax1=fig.add_subplot(311)
ax1.plot(np.linspace(0,50,150),w_list_mat[:,0])
plt.ylabel('x0')
ax2=fig.add_subplot(312)
ax2.plot(np.linspace(0,50,150),w_list_mat[:,1])
plt.ylabel('x1')
ax3=fig.add_subplot(313)
ax3.plot(np.linspace(0,50,150),w_list_mat[:,2])
plt.ylabel('x2')
plt.show()
可以看到,本图没有出现之前随机梯度算法参数weights的周期性波动,这归功于stocGradAscent1()里的样本随机选择机制,其次,可以看到,除了x1的微小波动外,x0,x2的很快就收敛,即改进的随机梯度算法收敛速度明显加快.