一、概述
1.简述:
logistic是一种线性分类器,针对的是线性可分问题。利用logistic回归进行分类的主要思想是:根据现有的数据对分类边界线建立回归公式,以此进行分类。这里的“回归”一词源于最佳拟合,表示要找到最佳拟合参数集,因此,logistic训练分类器时的做法就是寻找最佳拟合参数,使用的是最优化方法.
例如:在两个类的情况下,函数输出0或1,这个函数就是二值型分类器的sigmoid函数;
如图当x为0时,sigmoid的值为0.5,随着x的增大,对应的sigmoid函数值逼近1,随着x的减小,sigmoid函数的值逼近0
因此为了实现一个logistic回归分类器,可以在每个特征上都乘以一个回归系数,然后把所有的值相加,将这个总和代入sigmoid函数中得到一个0-1范围的数,任何大于0.5的数据归为1类,然后小于0.5的数据归为0类,logistic可以看做是一种概率估计。
2. Sigmoid函数
首先我们介绍一下Sigmoid函数,也称为逻辑函数:
其函数曲线如下:
逻辑回归的假设函数形式如下:
所以:
3.基于最优化方法的最佳回归系数确定
(1) 梯度上升法
梯度上升法基本的思想是:要找到某函数的 最大值,最好的方法是沿着该函数的梯度方向探寻。如果梯度记为∇,则函数f(x,y)的梯度由 下式表示:
(2) 梯度上升法
梯度下降算法,它与上述的梯度上升算法是一样的,只是公式中的加法需要变成减法。因此,对应的公式可以写成:
梯度上升算法用来求函数的最大值,而梯度下降算法用来求函数的最小值。
二、实现
1.准备数据:
2.使用梯度上升算法进行分类
(1)sigmoid函数:
# sigmoid函数
def sigmoid(inX):
return 1.0 / (1 + exp(-inX))
(2)梯度上升算法:
# 梯度上升算法
def gradAscent(dataMatIn, classLabels): # dataMatIn数据集、classLabels数据标签
dataMatrix = mat(dataMatIn) # 转换为NumPy矩阵
labelMat = mat(classLabels).transpose() # 转换为NumPy矩阵,并且矩阵转置
m, n = shape(dataMatrix) # 获取数据集矩阵的大小,m为行数,n为列数
alpha = 0.001 # 目标移动的步长
maxCycles = 500 # 迭代次数
weights = ones((n, 1)) # 权重初始化为1
for k in range(maxCycles): # 重复矩阵运算
h = sigmoid(dataMatrix * weights) # 矩阵相乘,计算sigmoid函数
error = (labelMat - h) # 计算误差
weights = weights + alpha * dataMatrix.transpose() * error # 矩阵相乘,更新权重
return weights
使用Logistic 回归方法进行分类并不需要做很多工作,所需做的只是把测试集上每个特征向量乘以最优化方法得来的回归系数,再将该乘积结果求和,最后输入到Sigmoid函数中即可。如果对应的Sigmoid值大于0.5就预测类别标签为1,否则为0。
def colicTest1():
# 读取测试集和训练集,并对数据进行格式化处理
frTrain = open("D:\syy\MachineLearning\data\dataTrain.txt") # 读取训练集文件
frTest = open('D:\syy\MachineLearning\data\dataTest.txt') # 读取测试集文件
trainingSet = [] # 创建数据列表
trainingLabels = [] # 创建标签列表
for line in frTrain.readlines(): # 按行读取
currLine = line.strip().split('\t') # 分隔
lineArr = []
for i in range(3):
lineArr.append(float(currLine[i]))
trainingSet.append(lineArr)
trainingLabels.append(float(currLine[3]))
# 使用改进的随即上升梯度训练
trainWeights = gradAscent(array(trainingSet), trainingLabels)
errorCount = 0 # 错误数
numTestVec = 0.0
for line in frTest.readlines(): # 遍历每行数据
numTestVec += 1.0 # 测试集数量加1
currLine = line.strip().split('\t')
lineArr = []
for i in range(3):
lineArr.append(float(currLine[i]))
if int(classifyVector(array(lineArr), trainWeights)) != int(currLine[3]):
errorCount += 1 # 预测结果与真值不一致,错误数加1
errorRate = (float(errorCount) / numTestVec) # 计算错误率
print("测试的错误率为: %f" % errorRate)
return errorRate
# 求结果的平均值
def multiTest():
numTests = 10
errorSum = 0.0
for k in range(numTests):
errorSum += colicTest1()
print("在 %d 迭代之后, 平均错误率为: %f" % (numTests, errorSum / float(numTests)))
结果:
从上述实验结果来看,使用逻辑回归进行性别分类的错误率较高
三、总结
1.优点
Logistic回归的模型结构简单,易于理解和实现。
计算速度相对较快,适合处理大量数据。
直接对分类的可能性建模,无需事先假设数据分布,避免了假设分布不准确带来的问题
2.缺点
容易欠拟合,分类精度不高
数据特征有缺失或特征空间很大时效果不好