机器学习04-logistic梯度下降算法
Posted Qunar_尤雪萍
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了机器学习04-logistic梯度下降算法相关的知识,希望对你有一定的参考价值。
logistic回归算法
我们将使用Logistic回归分类器来寻找最优值这是一个最优化算法问题。我们在k邻近算法中通过计算给定点到样本集合中所有点的距离,来判断该店所属于的类别,其实我们可以换一种解法,我们可以通过做一条直线将属于label1 和 label2 的两大类的点集进行区分,这样在给点点(x,y)可以通过判断(x,y)再直线的上方和下方来判断(x,y)的类别,那儿我们如何找到最适合的直线呢? 这里可能有一系列斜率值w直线,我们通过最优算法来确认最优质的w。
梯度下降算法
拟合曲线
对于给定的训练集我们可以使用曲线去做拟合,如下图:
我们可以为每个特征值赋一个权值w,这样我们就能得到我们的拟合曲线 hθ(x) = θ0 + θ1x1 + … θnxn = θx,回归算法的目的就是求出W的最佳权值。
损失函数
评估我们得到的θ是否合适,我们就需要使用损失算法去计算得到的W带入训练集得到的目标值和正确值之间的差异,这里我们采用平方差来定义损失函数。
要找到损失函数的最小值,我们可以采用梯度下降算法去获取,每次按照梯度减少的方向去调整我们的θ,最终能够找到符合损失范围的一个θ值。
这里我们就需要J(θ)对θ求偏导,最终得到偏导函数:
偏导函数乘于一个步长序数得到每次回归θ的减少值,下面是最终θ的回归公式:
在进行梯度下降寻找最小值时由于θ的初始值问题有可能最终得到的最小值时区域最小值而非全局最小值。如果我们最终要预测的值试一个0或1,这种时候我们已经可以使用单位阶跃函数Sigmoid f(z) = 1/(1+e-z) 其中-z是幂数,将hθ(x)带入其中当时f(z)>0.5时属于分类1,当f(z)<0.5时属于分类0。
使用梯度算法寻找最佳拟合直线
我们使用在knn里面的训练数据为它们寻找拟合曲线,训练数据分布:
首先按照往常使用下面脚本加载数据:
#-*- coding=utf-8 -*-
from numpy import *
from math import *
#加载数据的接口
def loadDataSet():
dataMat = [];labelMat = []
fr = open('testSet.txt')
for line in fr.readlines():
lineArr = line.strip().split("\\t")
#这里的1.0实际定义为 θ0的默认值
dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])])
labelMat.append(int(lineArr[2]))
return dataMat, labelMat
#定义我们的Sigmoid函数
def sigmiod(z):
return 1.0/(1 + exp(-z))
算法实现:
#训练算法
def dataTrain(dataMatIn, classLables):
#因为要使用矩阵方法,都先转换为矩阵
dataMatIn = mat(dataMatIn)
classLables = mat(classLables)
m,n = shape(dataMatIn)
#m表示测试数据量,n表示特征数
#我们为每个特征数指定一个默认的权值
weights = ones([n,1])
#设置每次移动的步长,这个步长是可以自己进行调整的
alpha = 0.001
#设置回归次数,其实有两种方法来终止回归,一种是指定回归次数,一种是指定误差值范围
maxCycles = 500
for k in range(maxCycles):
#获取预测结果 这里使用的是矩阵乘法 MxN * Nx1 = Mx1
h = sigmiod(dataMatIn*weights)
#获取误差值,相当于上面的求导公式里面的 hθ(x) - y
#当然这里的结果是一个矩阵向量 Mx1矩阵
error = (h - classLabels)
#一次回归θ 按照公式 θ = θ - alpha * error * dataMatIn
weights = weights - alpha * dataMatIn.transpose() * error
return weights
#分类方法
def classify(intX, weights):
value = sigmiod(inX * weights)
if value > 0.5:
return 1
return 0
#weight result:
matrix([[ 4.12414349],
[ 0.48007329],
[-0.6168482 ]])
最终得到的拟合直线:
随机梯度下降
上面的梯度算法我们的训练集总共有100个数据,回归次数500次,每次回归我们都会涉及到对所有训练集进行计算,计算复杂度太高。因此引出了我们的随机梯度下降算法,该算法一次仅适用一个样本点来更新回归系数,这个算法能够实现在线学习算法,当新样本到达时我们就可以对分类器做增量更新。
算法实现:
def randomDataTrain(dataMatIn, classLabels):
m,n = shape(dataMatIn)
classLabels = mat(classLabels)
weights = ones(n)
alpha = 0.1
for i in range(m):
#这里是array数组相乘
h = sigmoid(sum(dataMatIn[i]*weights.transpose()))
error = h - classLabels[i] #一次回归
weights = weights - alpha * mat(dataMatIn[i]) * error return weights
weights result:
matrix([[ 2.38604812, 0.95218922, -0.72978254]])
拟合曲线绿色的之前表示随机梯度下降得到的值:
这里可以看出得到的权值并不是最优权值,原因是因为我们的训练集合样本太少。但这并不能说明随机算法比上面的循环算法差,判断一个算法的优劣应该是看它是否收敛,参数是否达到稳定值。
补充
上面的随机梯度下降算法存在一个挺严重的问题是,由于每次使用其中的一条数据进行训练,会出现由于训练集合里面存在异常的数据项,从而导致我们的特征权值出现比较严重的波动,最终影响算法的收敛,针对这个问题我们可以进行改进。
def stocGradAscent1(dataMatrix, classLabels, numIter=150):
m,n = shape(dataMatrix)
weights = ones(n) #initialize to all ones
for j in range(numIter):
dataIndex = range(m)
for i in range(m):
#随着循环次数的增加使得我们的每次移动的步长值减少
alpha = 4/(1.0+j+i)+0.0001
#go to 0 because of the constant
randIndex = int(random.uniform(0,len(dataIndex)))
h = sigmoid(sum(dataMatrix[randIndex]*weights))
error = classLabels[randIndex] - h
weights = weights + alpha * error * dataMatrix[randIndex]
del(dataIndex[randIndex])
return weights
以上是关于机器学习04-logistic梯度下降算法的主要内容,如果未能解决你的问题,请参考以下文章