自己动手写Logistic回归算法


假设一个数据集有n个样本,每个样本有m个特征,样本标签y为{0, 1}。

数据集可表示为:

 自己动手写Logistic回归算法


自己动手写Logistic回归算法

其中,x(ij)为第i个样本的第j个特征值,y(i)为第i个样本的标签。

X矩阵左侧的1相当于回归方程的常数项。

每个特征有一个权重(或系数),权重矩阵为:

自己动手写Logistic回归算法

开始可以将权重均初始化为1。

将特征及权重分别相乘得到Xw (即特征的线性组合,为n维列向量)。

经过Sigmoid函数处理得到预测值:

自己动手写Logistic回归算法


y为预测值(取值范围0-1),为n维列向量。

对于一个样本i,y(i)取值为1和0的概率分别是:

 自己动手写Logistic回归算法

自己动手写Logistic回归算法 

 

其中x(i)为第i个样本的特征向量,为m+1维行向量。

为了学习得到最佳的权重矩阵w,需要定义损失函数来优化。一个直观的想法是使用预测值y与观测值Y之间的误差平方和,但是这个损失函数是非凸函数,用梯度下降法不能得到全局极小值。所以我们采用最大似然法。

对于每一个样本,出现的概率为:

 自己动手写Logistic回归算法

 

假设n个样本相互独立,概率相乘。似然函数为:

自己动手写Logistic回归算法

 

取对数,变乘法为加法,得到对数似然函数:

自己动手写Logistic回归算法

 

这就是我们需要最大化的目标函数。

 

梯度法 

如采用梯度法,首先要对w求导:

自己动手写Logistic回归算法
其中,σ为Sigmoid函数。

 

最后使用梯度上升来更新权重:

自己动手写Logistic回归算法

其中α为步长。经过多次迭代后,求得似然函数的最大值及相应的w

 

牛顿法

如采用牛顿法,需要计算二阶导数:

 

自己动手写Logistic回归算法

这是一个m×m的矩阵,称为Hessian矩阵,用H表示。

如果定义:

 
自己动手写Logistic回归算法

 

则:

 自己动手写Logistic回归算法 

 

根据牛顿迭代公式:

自己动手写Logistic回归算法

 

经过有限次迭代,达到收敛。

 

预测分类

如果用来预测分类,进行如下运算:

自己动手写Logistic回归算法

如y(i) > 0.5 判定为1,如y(i) < 0.5,判定为0

 

权重系数与OR的关系

下面讨论一下权重w与OR的关系。

根据OR的定义:

 自己动手写Logistic回归算法

 

当其他特征值不变的情况下,某x(i)增加1,相应的和xw增加w(i),OR值变为原来的exp(w(i)) 倍。

 

Python程序代码

 

from  numpy  import  *
import  matplotlib.pyplot as plt
 
# 加载数据
def  loadDataSet():
     dataMat  =  []
     labelMat  =  []
     fr  =  open ( 'data/testSet.txt' )
     for  line  in  fr.readlines():
         lineArr  =  line.strip().split( ',' )
         dataMat.append([ 1.0 float (lineArr[ 0 ]),  float (lineArr[ 1 ])])
         labelMat.append( int (lineArr[ 2 ]))
     fr.close()
     return  dataMat, labelMat
 
# Sigmoid函数,注意是矩阵运算
def  sigmoid(inX):
     return  1.0 / ( 1 + exp( - inX))
 
# 梯度上升算法
def  gradAscent(dataMatIn, classLabels):
     dataMat  =  mat(dataMatIn)
     labelMat  =  mat(classLabels).transpose()
     m,n = shape(dataMat)
     alpha  =  0.01
     maxCycles  =  500
     weights  =  mat(ones((n, 1 )))
     weightsHis  =  [mat(ones((n, 1 )))]  # 权重的记录,主要用于画图
     for  in  range (maxCycles):
         =  sigmoid(dataMat * weights)
         error  =  labelMat  -  h
         weights  =  weights  +  alpha * dataMat.transpose() * error
         weightsHis.append(weights)
     return  weights,weightsHis
 
 
 
# 简单的随机梯度上升,即一次处理一个样本
def  stocGradAscent0(dataMatIn, classLabels):
     dataMat  =  mat(dataMatIn)
     labelMat  =  mat(classLabels).transpose()
     m,n = shape(dataMat)
     alpha  =  0.01
     weights  =  mat(ones((n, 1 )))
     weightsHis  =  [mat(ones((n, 1 )))]  # 权重的记录,主要用于画图
     for  in  range (m):
         =  sigmoid(dataMat[i] * weights)
         error  =  labelMat[i]  - 
         weights  =  weights  +  alpha *  dataMat[i].transpose()  *  error
         weightsHis.append(weights)
     return  weights,weightsHis
 
 
# 改进的随机梯度算法
def  stocGradAscent1(dataMatIn, classLabels, numIter):
     dataMat  =  mat(dataMatIn)
     labelMat  =  mat(classLabels).transpose()
     m,n = shape(dataMat)
     alpha  =  0.001
     weights  =  mat(ones((n, 1 )))    
     weightsHis  =  [mat(ones((n, 1 )))]  # 权重的记录,主要用于画图
     for  in  range (numIter):
         dataIndex  =  list ( range (m))
         for  in  range (m):
             alpha  =  4 / ( 1.0 + j + i) + 0.001   # 动态调整alpha
             randIndex  =  int (random.uniform( 0 , len (dataIndex)))  # 随机选择样本
             =  sigmoid(dataMat[randIndex] * weights)
             error  =  labelMat[randIndex] -  h
             weights = weights  +  alpha  *  dataMat[randIndex].transpose()  *  error
             del (dataIndex[randIndex])
             
         weightsHis.append(weights)
         
     return  weights,weightsHis
 
 
 
# 牛顿法
def  newton(dataMatIn, classLabels, numIter):
     dataMat  =  mat(dataMatIn)
     labelMat  =  mat(classLabels).transpose()
     m,n = shape(dataMat)
     # 对于牛顿法,如果权重初始值设定为1,会出现Hessian矩阵奇异的情况.
     # 原因未知,谁能告诉我
     # 所以这里初始化为0.01
     weights  =  mat(ones((n, 1 ))) - 0.99 
     weightsHis  =  [mat(ones((n, 1 )) - 0.99 )]  # 权重的记录,主要用于画图    
     for  in  range (numIter):
         =  eye(m)
         for  in  range (m):
             =  sigmoid(dataMat[i] * weights)
             hh  =  h[ 0 , 0 ]
             A[i,i]  =  hh * ( 1 - hh)
         
         error  =  labelMat  -  sigmoid(dataMat * weights)
         =  dataMat.transpose()  *  *  dataMat  # Hessian矩阵                
         weights  =  weights  +  H * * - 1  *  dataMat.transpose()  *  error
         
         weightsHis.append(weights)
         
     return  weights,weightsHis
     
     
def  plotWeights(w):      
     =  array(w)      
     def  f1(x):
         return  w[x, 0 , 0 ]
     def  f2(x):
         return  w[x, 1 , 0 ]
     def  f3(x):
         return  w[x, 2 , 0 ]          
     =  len (w)
     =  range ( 0 ,k, 1 )
     plt.plot(x,f1(x),' ',x,f2(x),' ',x,f3(x),' ')
     plt.show()
     
 
# 画出分类边界
def  plotBestFit(wei):
     weights  =  wei.getA()
     dataMat, labelMat  =  loadDataSet()
     dataArr  =  array(dataMat)
     =  shape(dataArr)[ 0 ]
     xcord1 = []
     ycord1 = []
     xcord2 = []
     ycord2 = []
     for  in  range (n):  
         if  int (labelMat[i]) = = 1 :
             xcord1.append(dataArr[i, 1 ])
             ycord1.append(dataArr[i, 2 ])
         else :
             xcord2.append(dataArr[i, 1 ])
             ycord2.append(dataArr[i, 2 ])
     fig  =  plt.figure()
     ax  =  fig.add_subplot( 111 )
     ax.scatter(xcord1, ycord1, s = 30 , c = 'red' , marker = 's' )
     ax.scatter(xcord2, ycord2, s = 30 , c = 'green' )
     =  arange( - 3.0 , 3.0 , 0.1 )
     y = ( - weights[ 0 ] - weights[ 1 ] * x) / weights[ 2 ]
     ax.plot(x,y)
     plt.xlabel( 'x1' )
     plt.ylabel( 'x2' )
     plt.show()
 
# 测试    
data, labels  =  loadDataSet()
#weights,weightsHis = gradAscent(data, labels)
#weights0, weightsHis0 = stocGradAscent0(data, labels)
#weights1, weightsHis1 = stocGradAscent1(data, labels, 500)
weights3, weightsHis3  =  newton(data, labels,  10 )
 
plotBestFit(weights3)
print (weights3)
plotWeights(weightsHis3)
 
 

运行结果:

 
1、梯度法迭代500次的分类边界及权重收敛情况
自己动手写Logistic回归算法
自己动手写Logistic回归算法
2、随机梯度法迭代500次的分类边界及权重收敛情况
自己动手写Logistic回归算法

自己动手写Logistic回归算法
3、牛顿法迭代10次的分类边界及权重收敛情况,可以牛顿法要快很多。
自己动手写Logistic回归算法

自己动手写Logistic回归算法
转载于:http://blog.sina.com.cn/s/blog_44befaf60102wbbr.html
 
 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM