线性模型可以进行回归学习,但是若要做分类任务该怎么办,只需要找一个单调可微函数将分类任务的真实标记y与线性回归的预测值联系起来。
对数几率函数(logistic function)(逻辑斯蒂回归):
对数几率函数是一种Sigmoid函数,将z值转化为一个接近0或者1的y值,并且其输出值在z=0附近变化很陡。
将y视为样本x作为正例的可能性,1-y则是反例的可能性,两者的比值为
称为几率。反应了x作为正例的可能性。
可以看出,
是用线性回归模型的预测结果去逼近真实标记的对数几率,因此,其对应模型称为对数几率回归。需要注意的是名字带有回归,实际上式分类方法。
这种方法的优点包括:直接对分类可能性进行建模,无需事先假设数据分布,避免假设分布不准确所带来的问题,不是仅仅预测出类别,而是可以得到近似概率预测,这对许多需要利用概率辅助决策的任务很有用,此外,对率函数是任意阶可导的凸函数,有很好的数学性质,现在的许多数值优化算法都可直接用于求取最优解。
如何确定其中的w和b。将y视为类后验概率
,则:
,有
,
,然后可以通过极大似然大来估计w和b。
给定数据集,对率回归模型最大化对数似然,
,即令每个样本术语其真实标记的概率越大越好。
令
,
,则
,将其带入上式,
,该式子是关于
的高阶可导连续函数,可以通过经典的数值优化算法梯度下降法、牛顿法等求得其最优解。
梯度下降法实现代码:
梯度下降w迭代公式为:
# 代码以及数据集源自于机器学习实战,见https://github.com/AnnDWang/MachineLearning/blob/master/thirdbook/ch5/logRegres.py
# logistic 回归梯度上升优化算法
def loadDataSet():
dataMat=[]
labelMat=[]
fr=open('testSet.txt')
for line in fr.readlines():
lineArr=line.strip().split()
dataMat.append([1.0,float(lineArr[0]),float(lineArr[1])])
labelMat.append(int(lineArr[2]))
return dataMat,labelMat
def sigmoid(inX):
return 1.0/(1+exp(-inX))
def gradAscent(dataMatIn,classLabels):
dataMatrix=mat(dataMatIn)
labelMat=mat(classLabels).transpose()
m,n=shape(dataMatrix)
alpha=0.001
maxCycles=500
weights=ones((n,1))
for k in range(maxCycles):
h=sigmoid(dataMatrix*weights)
error=(labelMat-h)
weights=weights+alpha*dataMatrix.transpose()*error
return weights
dataArr,labelMat=loadDataSet()
weights=gradAscent(dataArr,labelMat)
# 随机梯度上升算法
def stocGradAscent0(dataMatrix,classLabels):
m,n=shape(dataMatrix)
alpha=0.01
weights=ones(n)
for i in range(m):
h=sigmoid(sum(dataMatrix[i]*weights))
error=classLabels[i]-h
weights=weights+alpha*error*dataMatrix[i]
return weights
# 改进的随机梯度上升算法
# alpha在每次迭代时候都会调整,这回缓解数据波动或者高频波动
# 虽然alpha会随着迭代次数不断减小,但永远不会减小到0
# 这是因为alpha更新公式中存在一个常数项,保证多次迭代之后新数据仍然有一定的影响
# 如果要处理的问题是动态变化的,那么可以适当加大常数项,来确保新的值获得更大的回归系数
# 在降低alpha函数中,每次减少1/(j+i),其中j是迭代次数,i是样本点的下标,
# 这样当j<<max(i)时,alpha就不是严格下降的
# 避免参数的严格下降也常见于模拟退火等其他优化算法
def stocGradAscent1(dataMatrix,classLabels,numIter=150):
m,n=shape(dataMatrix)
weights=ones(n)
for j in range(numIter):
dataIndex=list(range(m))
for i in range(m):
alpha=4/(1.0+j+i)+0.01 # alpha在每次迭代时候都会调整
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
上述介绍的是二项分类模型,用于二类分类,可以将其推广为多项逻辑斯蒂回归模型,用于多类分类,假设离散型随机变量Y的取值集合是{1,2,...,K},那么多项逻辑斯蒂回归模型是:
,