逻辑回归是回归系列中一个分类模型,而且是一个二分类模型。逻辑回归模型简单但应用广泛,本文从模型介绍、适用场景以及优缺点等几个方面介绍下。
模型介绍
介绍模型之前, 先了解一个数学函数:sigmoid 函数
其函数图像如下:
sigmoid函数值在【0,1】之间, 在离x较远的地方, 函数值无限接近0或者1。逻辑回归就是利用sigmoid的这个性质构建。
利用函数sigmoid构建的逻辑回归的概率函数:
P(y=1 | x; θ) 表示分类结果为1的概率, θT * X表示参数向量与自变量X的点积, 作为sigmoid函数的输入, 得到一个【0,1】之间的值。作为分类模型, 做如下定义:
其中y*是分类结果, 当P(y=1 | x; θ) 大于0.5, 分类结果为1;小于0.5, 分类结果为0.
通俗点说:利用sigmoid函数的特殊数学性质, 将θT * X结果映射到【0,1】的一个概率值,设定一个概率阈值(不一定非是0.5),大于这个阈值分类为1, 小于则分类为0.
模型参数
模型参数的求解方法之一:采用最大似然估计的对数形式(对数是单调函数, 求解参数的最大值,函数的对数和函数求出的最大解是一样的)构建函数, 再利用前面介绍的梯度下降来求解。
梯度下降求解对数似然函数:
得到参数的迭代公式:
模型的适用场景
用于分类场景, 尤其是因变量是二分类, 比如垃圾邮件判断(是/否垃圾邮件),是否患某种疾病(是/否), 广告是否点击等场景。
模型的优缺点
缺点:
逻辑回归需要大样本量,因为最大似然估计在低样本量的情况下不如最小二乘法有效。
防止过拟合和欠拟合,应该让模型构建的变量是显著的。
对模型中自变量多重共线性较为敏感,需要对自变量进行相关性分析,剔除线性相关的变量。
优点:
模型更简单,好理解,实现起来,特别是大规模线性分类时比较方便
模型实践
参考机器学习实践书中逻辑回归章节, 实现判断马是否得疝气病案例。
采用随机梯度下降方法求取weights, 分测试集和训练集对逻辑回归模型进行测试。
有两个值得注意的点:
1.随机梯度下降函数stocGradAscent中,weights更新会加上循环
for i in range(m)
不是很明白为啥, 加上以后计算量和批量梯度差不多。尝试去掉这个循环, 但误差变得不稳定, 有的次数误差达到0.5+。如果不去掉, 基本保持在0.3+以内。
- stocGradAscent函数中alpha的更新
alpha = 4 / (1.0 + i + j ) + 0.01
alpha不是一个固定的值, 而是随着数据下标i, 迭代次数j的变大, 而变小。对比测试, 发现能有效地让weights更稳定,不会再小区域内来回波动。 尚不知为何这样设置alpha的更新策略, 后续学习。
#coding=utf-8
import numpy as np
from numpy import *
#sigmoid函数定义
def sigmoid(inX):
return 1.0/(1+exp(-inX))
#以概率0.5为阈值, 大于0.5判断类型为1,否则为0
def classifyBySigmoid(xVectors, wVectors):
p = sigmoid(sum(xVectors*wVectors))
if p > 0.5:
return 1
else:
return 0
#读取文本数据
def readDatasetFromFile(path, labelIndex):
data_file = open(path)
dataSet = []
dataLabel = []
for line in data_file.readlines():
currLine = line.strip().split('\t')
lineArr = []
for i in range(21):
lineArr.append(float(currLine[i]))
dataSet.append(lineArr)
dataLabel.append(float(currLine[labelIndex]))
return dataSet, dataLabel
# 随机梯度上升函数
# dataMatrix X自变量向量集合
# classLabels Y因变量向量,逻辑回归中是0或者1的集合
# numIters 迭代次数
def stocGradAscent(dataMatrix, classLabels, numIters=150):
m,n = shape(dataMatrix)
weights = ones(n)
for j in range(numIters):
dataIndex = range(m)
#随机梯度算法, 可以去除这个循环?加上和批量梯度下降相比,计算量貌似没有降低
for i in range(m):
alpha = 4 / (1.0 + i + j ) + 0.01
randIndex = int(random.uniform(0, len(dataIndex)))
h = sigmoid(sum(weights * dataMatrix[randIndex]))
error = classLabels[randIndex] - h
weights = weights + alpha * error * dataMatrix[randIndex]
del(dataIndex[randIndex])
return weights
def logisticTrain():
trainingSet = []
trainingLabel = []
testSet = []
testLabel = []
trainSet, trainLabel = readDatasetFromFile("../../../data/lr/horseColicTraining.txt", 21)
testSet, testLabel = readDatasetFromFile("../../../data/lr/horseColicTest.txt", 21)
weights = stocGradAscent(array(trainSet), trainLabel, 500)
errorNo = 0
totalNo = 0
for i in range(len(testSet)):
totalNo += 1
tempLabel = classifyBySigmoid(array(testSet[i]), weights)
if (tempLabel != testLabel[i]):
errorNo += 1
errorRate = float(errorNo) / totalNo
print "the error rate of test set: " + str(errorRate)
return errorRate
if __name__ == '__main__':
error_sum = 0.0
for i in range(10):
error_sum += logisticTrain()
print "the 10 iterations the average error rate is : " + str(error_sum / 10)
PS:简书貌似不可以传数据附件,贴出机器学习实战的下载地址, 解压后第5章可以找到相关代码和数据。
https://manning-content.s3.amazonaws.com/download/3/29c6e49-7df6-4909-ad1d-18640b3c8aa9/MLiA_SourceCode.zip