这次接触点的 logistic 回归,一种最优化算法,根据现有的数据对分类边界建立回归公式,一次进行分类,这里的回归源于最佳的拟合,表示要找到最佳的拟合参数集,训练分类器时的做法就是寻找最佳的拟合参数,用来获得一个二值型输出分类器的数学原理。
基于 Logistic 回归 和 Sigmod 函数的分类
由于需要一个能够接收所有的参数并输出二值型预测值的函数,我们需要 Sigmoid 函数:
σ ( z ) = 1 1 + e x \sigma(z)=\frac{1}{1+e^{x}} σ(z)=1+ex1
函数图像如下:
我们将每个参数都成一个回归系数w,并将其所有求和,作位z带入该函数,使得当z输出小于0时为0,大于零时为1,从而达到根据输入的参数进行分类的效果。
那么现在的问题就在与w的取值,如何求得最佳回归系数。
最佳回归系数的确定
使用随机梯度上升算法来确定最佳回归系数,来获得最优解。主要思想:要找到某个函数的最大值,最好的方法时沿着该函数的梯度方向探寻,在不同方向有不同的梯度写成向量形式:
w : = w + α ▽ w f ( w ) w:=w+\alpha\triangledown _wf(w) w:=w+α▽wf(w)
α \alpha α 为每次的步进长, ▽ w \triangledown_w ▽w表示的不同回归参数多对应的向量。
下面是通过梯度上升算法计算最佳回归参数的代码:
def sigmoid(inX):
return 1.0/(1+exp(-inX)
def gradAscent(dataMatin, classLabels):
dataMatrix = mat(dataMatin)
labelMat = mat(classLbels).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)
weigths = weights + alpha * dataMatrix.transpose() * error
return weights
在循环中我们实现了梯度上升,这里所求的最大值是数据的拟合函数的最大值,类似于误差函数的最小值(我们这里用的是梯度上升法所以是求拟合函数的最大值),通过推导可以得到循环中的weigths的表达式。
在循环过程中每次矩阵运算会进行 m*n 次乘法,在经过多次迭代,会是计算量变得很大,所以我们对程序进行改进,使用随机梯度上升。
改进代码如下:
def stocGradAscent0(dataMatrix, classLabels):
m, n = shape(dataMatrix)
alpha = 0.01
weights = one(n)
for i in range(m):
h = sigmoid(sum(dataMatrix[i]*weights))
error = classLabels[i] - h
weights = weight + alpha * error * dataMatrix[i]
return weights
这次我们每次迭代都是使用的数据中的一组,而不是整个矩阵,运算减少了。不过只进行一次迭代的分类效果是不好的,我们可以适当增加迭代的次数,来是回归参数收敛,但是还会出现带收敛的时候回归参数在渐近线附近波动较大,这是因为有不正确的分类样本点(数据集并非线性可分),我们再次改进程序解决这个问题。
改进代码如下:
def stocGradAscent1(dataMatrix, classLabels, numIter=150):
m, n = shape(dataMatrix)
weights = one(n)
for j in range(numIter):
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 = weight + alpha * error * dataMatrix[randIndex]
del(dataMatrix[randIndex])
return weights
为避免波动过大,我们每次都改变alpha的值,同时alpha会随着迭代次数不断减小,另一个改进的地方,我们采用随机采取样本的方式,减少回归参数的周期性波动。
这是改进前的收敛情况
这是改进后的收敛情况:
这里我们可以发现改进后到收敛所需计算次数明显减少。