努利家族的正则响应函数就是sigmoid函数,因此逻辑回归为什么选用sigmoid函数的理论原因。同时,sigmoid函数好处有:

  1. 将现行分类器的响应值 <w , x> (内积) 映射到一个概率上;

  2. 将实域上的数映射到P(y=1|w,x)上,满足逻辑回归的要求。

  逻辑回归可以用于二分类问题,只能解决线性可分的情况,不能用于线性不可分。

  对于输入向量X,其属于y=1的概率为:

svyglm函数计算逻辑回归 逻辑回归sigmoid函数的好处_损失函数

其属于y=0的概率为:

svyglm函数计算逻辑回归 逻辑回归sigmoid函数的好处_随机梯度下降_02

对于逻辑回归函数,其属于y的概率为:

svyglm函数计算逻辑回归 逻辑回归sigmoid函数的好处_迭代_03

  逻辑回归模型需要求得参数向量W,可以使用极大似然估计求解。假设有m个样本,则似然函数为:

svyglm函数计算逻辑回归 逻辑回归sigmoid函数的好处_svyglm函数计算逻辑回归_04

取对数可得损失函数:

svyglm函数计算逻辑回归 逻辑回归sigmoid函数的好处_svyglm函数计算逻辑回归_05

根据极大似然估计的理论,要使得参数最优,则似然函数需要最大,因此上式需要求最大值:svyglm函数计算逻辑回归 逻辑回归sigmoid函数的好处_svyglm函数计算逻辑回归_06

  逻辑回归损失函数是一个凸函数,其凸优化求解方法有很多,如梯度下降、随机梯度下降、牛顿法等。

   逻辑函数的损失函数进一步化简过程如下:

svyglm函数计算逻辑回归 逻辑回归sigmoid函数的好处_svyglm函数计算逻辑回归_05

svyglm函数计算逻辑回归 逻辑回归sigmoid函数的好处_迭代_08

svyglm函数计算逻辑回归 逻辑回归sigmoid函数的好处_随机梯度下降_09

svyglm函数计算逻辑回归 逻辑回归sigmoid函数的好处_随机梯度下降_10

svyglm函数计算逻辑回归 逻辑回归sigmoid函数的好处_svyglm函数计算逻辑回归_11

svyglm函数计算逻辑回归 逻辑回归sigmoid函数的好处_损失函数_12

其中,第四步到第五步的化简,上下同除svyglm函数计算逻辑回归 逻辑回归sigmoid函数的好处_随机梯度下降_13

  对损失函数求导,可得到其梯度,过程如下:

svyglm函数计算逻辑回归 逻辑回归sigmoid函数的好处_迭代_14

svyglm函数计算逻辑回归 逻辑回归sigmoid函数的好处_svyglm函数计算逻辑回归_15

svyglm函数计算逻辑回归 逻辑回归sigmoid函数的好处_svyglm函数计算逻辑回归_16

svyglm函数计算逻辑回归 逻辑回归sigmoid函数的好处_迭代_17

  由上式可以看出,逻辑回归的参数W的梯度是每个样本标签值与其计算值的偏差乘以该样本的对应值,然后对所有样本累计求和,如下图所示。

svyglm函数计算逻辑回归 逻辑回归sigmoid函数的好处_迭代_18

   逻辑回归的Python代码如下:

 

# -*- coding: utf-8 -*-
"""
Created on Wed Jan 17 13:33:28 2018

@author: zhang
"""

##针对梯度上升求最大似然估计,可先设置大一点的步长与0.02, 求取一个初步的最优解, 然后设置小一点的步长,进一步求取精度更高的参数

import numpy as np
import time 
from sklearn.datasets import load_breast_cancer
from sklearn.cross_validation import train_test_split

def load_data ():
     dataSet = load_breast_cancer()
     
     return dataSet.data, dataSet.target
     
     
def sigmoid (X):
     return 1.0 / (1.0 + np.exp(-X))

def LR_train (train_x, train_y, maxCycle, alpha):
     
     numSamples, numFeatures = np.shape(train_x)
     weights = np.ones((numFeatures, ))  
     
#     需要注意 np.ones((numFeatures, )) 和 np.ones((numFeatures, 1)) 的区别,虽然其数值是一样的,但是索引不同
#     此处选择第一种是为了与数据集中的形式匹配
     
     for i in range(maxCycle):
          
          #梯度下降,用到所有样本, 通过所有样本找到梯度,然后调整权重, 需要多次迭代才能收敛(实验为500次)
#          output =sigmoid(np.dot(train_x, weights))
#          err = train_y - output
#          weights = weights + alpha * np.dot(train_x.transpose(), err)
          
          # SGD  随机梯度下降,每次用单个样本计算梯度方向,此处为因此用到所有样本计算梯度,收敛快,迭代次数少(实验为10次)。因样本少,所以
          # 两者计算时间相差不大,当数据量大时,SGD理论收敛要快计算时长要少
          for i in range(numSamples):
               output =sigmoid(np.dot(train_x[i,:], weights))
               err = train_y[i,] - output
               weights = weights + alpha * np.dot(train_x[i,:].transpose(), err)   
          
     return weights


def LR_test (test_x, test_y, weights):
     numSamples, numFeatures = np.shape(test_x)
     count = 0
     for i in range(numSamples):   
          if sigmoid(np.dot(test_x[i,:], weights)) > 0.5:  
               predict = 1
          else: 
               predict = 0
          if predict == test_y[i,]:
                count = count + 1
     return float(count/numSamples)

if __name__ == "__main__":
     data, label = load_data()  
     startTime = time.time()       
     train_x, test_x , train_y, test_y=train_test_split(data, label,test_size=0.25, random_state=33)
        
     weights = LR_train (train_x, train_y, 10, 0.01) 

     accuracy = LR_test (test_x, test_y, weights)
     
     print("准确率:"+ str(accuracy))
     print("计算时长:" +str(time.time() - startTime))