目录
-
Logistic原理
我们想要的函数应该是,能接受所有的输入然后预测出类别。例如,在两个类的情况下,上述函数输出0或1。这种性质的函数,称为海维塞德阶跃函数( Heaviside step function ),或者直接称为单位阶跃函数。然而,海维塞德阶跃函数的问题在于:该函数在跳跃点上从0瞬间跳跃到1,这个瞬间跳跃过程有时很难处理。幸好,另一个函数也有类似的性质R,且数学上更易处理,这就是Sigmoid函数。Sigmoid函数具体的计算公式如下:
图下给出了Sigmoid函数在不同坐标尺度下的两条曲线图。当x为0时,Sigmoid函数值为0.5。随着x的增大,对应的Sigmoid值将逼近于1;而随着x的减小,Sigmoid值将逼近于0。如果横坐标刻度足够大,Sigmoid函数看起来很像一个阶跃函数。
因此,为了实现Logistic回归分类器,我们可以在每个特征上都乘以一个回归系数,然后把所有的结果值相加,将这个总和代人Sigmoid函数中,进而得到-一个范围在0~1之间的数值。任何大于0.5的数据被分入1类,小于0.5即被归入0类。所以,Logistic回归也可以被看成是一种概率估计。
确定了分类器的函数形式之后,现在的问题变成了:最佳回归系数是多少?如何确定它们的大小?、
Sigmoid函数的输入记为z,由下面公式得出:
如果采用向量的写法,上述公式可以写成,它表示将这两个数值向量对应元素相乘然后全部加起来即得到z值。其中的向量x是分类器的输入数据,向量w也就是我们要找到的最佳参数(系数)从而使得分类器尽可能地精确。为了寻找该最佳参数,需要用到最优化理论的一些知识。
-
梯度上升的最优化方法
接下来,展示如何绘制梯度上升法产生的决策边界图,该图能将梯度上升法的分类效果可视化地呈现出来。最后我们将学习随机梯度上升算法,以及如何对其进行修改以获得更好的结果。
就好比是爬山,当不断向上快到山顶的时候,我们也就越接近极值。
我们最经常听到的应该是梯度下降算法,它与这里的梯度上升算法是一样的,只是公式中的加法需要变成减法。
梯度上升法基本的思想是:要找到某函数的 最大值,最好的方法是沿着该函数的梯度方向探寻。如果梯度记为∇,则函数f(x,y)的梯度由 下式表示:
这个梯度意味着要沿x的方向移动 ,沿y的方向移动 。其中,函数f(x,y) 必须要在待计算的点上有定义并且可微。如下图:
梯度上升对应的公式可以写成:
梯度下降对应的公式可以写成:
他们的区别是梯度上升算法用来求函数的最大值,而梯度下降算法用来求函数的最小值。
logistic实例分析
利用Logistic回归模型根据身高、体重和肺活量预测性别
准备数据
使用梯度上升算法进行分类
sigmoid函数:
# sigmoid函数
def sigmoid(inX):
return 1.0 / (1 + exp(-inX))
梯度上升算法:
# 梯度上升算法
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 classifyVector(inX, weights):
prob = sigmoid(sum(inX * weights)) # 计算sigmoid值
if prob > 0.5: # 概率大于0.5,返回分类结果1.0
return 1.0
else: # 概率小于等于0.5,返回分类结果0.0
return 0.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)))
运行结果如图:
小结
Logistic回归的目的是寻找一个非线性函数Sigmoid的最佳拟合参数,求解过程可以由最优化算法来完成。在最优化算法中,最常用的就是梯度上升算法,而梯度上升算法又可以简化为随机梯度上升算法。
随机梯度上升算法与梯度上升算法的效果相当,但占用更少的计算资源。此外,随机梯度上升是一个在线算法,它可以在新数据到来时就完成参数更新,而不需要重新读取整个数据集来进行批处理运算。
逻辑回归的优点:直接对分类的可能性建模,无需事先假设数据分布,避免了假设分布不准确带来的问题,不仅预测出类别,还可得到近似概率预测
缺点:容易欠拟合,分类精度不高,数据特征有缺失或特征空间很大时效果不好