假设我们现在有一些数据点,我们用一条直线对这些点进行拟合(该线称为最佳拟合直线),这个拟合过程称作回归。利用Logistic回归进行分类的主要思想是:根据现有数据对分类边界线建立回归公式,以此进行分类。这里的“回归”一词源于最佳拟合,表示要找到最佳拟合参数集。训练分类器时的做法就是寻找最佳拟合参数,使用的是最优化算法。
1.1 基于Logistic回归和Sigmoid函数的分类
我们想要的函数应该是,能接受所有的输入然后预测出类别。例如,在两个类的情况下,上述函数输出0与1,这就是Sigmoid函数,具体的计算公式如下:
Δ(z)=11+e−z
当x为0时,Sigmoid函数值为0.5.随着x的增大,对应的Sigmoid值将逼近于0。因此,为了实现Logistic回归分类器,我们可以在每个特征上都乘以一个回归系数,然后把所有的结果值相加,将这个总和代入Sigmoid函数中,进而得到一个范围在0~1之间的数值。任何大于0.5的数据被分入1类,小于0.5即被归入0类。所以Logistic回归也可以被看成是一种概率估计。
1.2 基于最优化方法的最佳回归系数确定
1.2.1 梯度上升法
梯度上升法基于的思想是:要找到某函数的最大值,最好的方法是沿着该函数的梯度方向探寻。梯度算子总是指向函数值增长最快的方向。这里所说的是移动方向,而未提到移动量的大小。该量值称为步长,记做
α
。用向量来表示的话,梯度上升算法的迭代公式如下:
ω=ω+α∇f(ω)
该公式将一直被迭代执行,直至达到某个停止条件为止,比如迭代次数达到某个指定值或算法达到某个可以允许的误差范围。
1.2.2 随机梯度上升
梯度上升算法在每次更新回归系数时都需要遍历整个数据集,该方法在处理100个左右的数据集时尚可,但如果有数十亿样本或成千上万的特征,那么该方法的计算复杂度就太高了。一种改进方法是一次仅用一个样本点来更新回归系数,该方法称为随机梯度上升算法。由于可以在新的样本到来时对分类器进行增量式更新,因而随机梯度上升算法是一个在线学习算法。与在线学习相对应,一次处理所有的数据被称作是批处理。
程序清单1-1 改进的随机梯度上升算法
def stocGradAscent1(dataMatrix,classLabels,numIter = 150):
m,n = shape(dataMatrix)
weights = ones(n)
for j in range(numIter):
dataIndex = range(m)
for i in range(m):
alpha = 4/(1.0+j+i)+0.01
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
1.3 示例:从疝气病症预测病马的死亡率
将原始数据经过缺失处理得到两个文件:horseColicTraining.txt和horseColicTest.txt。下面看看运行Logistic回归的分类效果。
程序清单1-2 Logistic回归分类函数
def sigmoid(inX):
return 1.0/(1+exp(-inX))
def classifyVector(inX,weights):
prob = sigmoid(sum(inX*weights))
if prob > 0.5:
return 1.0
else:
return 0.0
def colicTest():
frTrain = open('horseColicTraining.txt')
frTest = open('horseColicTest.txt')
trainingSet = [];trainingLabels = []
for line in frTrain.readlines():
currLine = line.strip().split('\t')
lineArr = []
for i in range(21):
lineArr.append(float(currLine[i]))
trainingSet.append(lineArr)
trainingLabels.append(float(currLine[21]))
trainWeights = stocGradAscent1(array(trainingSet),trainingLabels,500)
errorCount = 0.0; numTestVec = 0.0
for line in frTest.readlines():
numTestVec += 1.0
currLine = line.strip().split('\t')
lineArr = []
for i in range(21):
lineArr.append(float(currLine[i]))
if int(classifyVector(array(lineArr),trainWeights))!=int(currLine[21]):
errorCount += 1
errorRate = (float(errorCount)/numTestVec)
print "the error rate of this test is: %f"%errorRate
return errorRate
def multiTest():
numTests = 10;errorSum = 0.0
for k in range(numTests):
errorSum += colicTest()
print "after %d iterations the average error rate is:%f" %(numTests,errorSum/float(numTests))
最后一个函数是multiTest(),其功能是调用函数colicTest()10次并求结果的平均值。