Machine Learning-Logistic
标签 : MachineLearning 人工智能
算法概述
Logistic回归是建立在最优化算法之上的回归方法。利用Logistic回归进行分类的主要思想是根据现有数据对分类边界线建立回归公式,以此进行分类。Logistic回归进行分类的优点是其计算代价不高,易于实现;但是同时也容易欠拟合,导致分类的精度不够高。Logistic回归同样适用于数值型和标称型数据。
算法准备
Sigmoid函数
首先回顾Sigmoid函数。我们需要的分类函数应该具有接受所有输入然后预测出类别的功能,首先想到的单位阶跃函数,但是单位阶跃函数的问题在于在“0”与“1”之间转换是瞬间的,无法求导,难以处理。Sigmoid函数也是一种阶跃函数,其优势在于由“0”到“1”的变换是连续可导的,因此易于处理。具体公式如下:
在z=wx的情况下,分别给出w=0.5和w=2的两种特殊情况下函数图像:
一般情况下,Sigmoid函数的输入z需要接受更多的输入属性,其表达式如下:
向量表达形式如下:
在Logistic回归中,参数$w^T$为模型需要训练的参数。
梯度上升法
梯度上升法属于最优化算法,其目的是寻找符合条件的最大值。梯度上升法的基本思想是:要寻找函数的最大值,最好的方法是沿着该函数梯度方向搜寻。其迭代公式为:
其中alpha为训练的步长。该公式将一直被迭代执行到某个停止条件位置,例如迭代次数达到规定迭代次数,或者算法使误差达到规定允许的误差范围之内。
与其相似的是梯度下降算法,其原理与梯度上升一样,目的是寻找符合条件的最小值,实现也只是在梯度上升的迭代公式中,将加法换为减法即可,此部分的证明和实现可以参考Ng的机器学习课程,讲述较为详细。
算法思路
Logistic回归是基于Sigmoid函数基础上的回归方法,即为回归则需要建立回归公式,在回归公式的基础上进行分类,而所使用的回归公式则为Sigmoid函数。算法的整体思路是利用有标签的样本集和相应的最优化算法,经过训练,最优化Sigmoid函数中的参数w。再有新的样本点需要进行分类时,则将样本点的属性值带入参数优化后的Sigmoid函数,得到一个对应的函数值,利用其进行分类。更直观表述是,如果样本点的属性是二维的,则可以将不同种类的样本点利用不同的形状表示在二维坐标图上,而Logistic回归需要做的是找到一条相应直线,使得不同的样本点分别位于边界线的两边;边界线需要的两个系数即为算法需要训练的参数。
在进行参数优化的时候的优化算法不唯一,例如梯度上升和梯度下降,需要注意的是,两种方法成本函数是不一样的。梯度下降方法目的是最小化成本函数,其成本函数是基于样本实际标签和预测标签的距离上的函数,其目的是找到使得两者差距最小的参数,详细过程可以参考Ng的机器学习课程;梯度上升方法的目的是最大化成本函数,其成本函数是基于最大似然估计的成本函数,《MachineLearninginAction》中使用的是此方法,但是具体推导过程需要自己推导。Ng的机器学习课程中还介绍了一种法方法,具体参见Ng的相关课程资料。
梯度上升算法和梯度下降方法都可以进行进一步的优化。以梯度上升方法为例,改进方法有两种思路。第一种思路是考虑到若单次训练更新参数需要遍历整个数据集,则其计算成本过高,改进的方法是单步训练更新只使用一个样本点,从而减小计算成本。第二种思路是基于训练步长考虑的,有梯度上升算法的性质可知,在约接近最优值的地方,如果仍保持原始步长则算法不易直接到达最优值,而是会绕最优值进行环绕,具体证明可以参考Ng的机器学习课程,所以我们随着迭代次数的增加,不断减小步长。这样优化之后,步长不会减小到零,应为存在一个较小的常数项。梯度下降的优化思路与梯度上升同。
算法实现
本文中Logistic回归最优化方法选择梯度上升方法,实现的参考《MachineLearnigninAction》。
核心函数分析如下:
1 | def gradAscent(dataMatIn,classLabels): |
此函数为参数训练函数,其中输入参数“dataMatIn”为样本集的特征,“classLabels”为样本集的标签。“alpha”为步长,“maxCycles”为迭代次数,输出“weights”为训练好的Sigmoid函数的参数。代码循环中公式为推导好的迭代公式。1
2
3
4
5
6
7
8
9def 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
此函数为改进后的训练函数,是在随机梯度上升算法的基础上进行的优化,输入输出与上同,实现随机梯度上升算法,可以发现,循环训练中由每次迭代所有样本点改进为只利用一个样本点进行迭代,降低计算成本。1
2
3
4
5
6
7
8
9
10
11
12
13def stocGradAscent1(dataMatrix,classLabels,numIter=150):
m,n = shape(dataMatrix)
weights = ones(n)
for j in range(m):
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
此函数是对于步长改进后的训练函数,步长“alpha”随迭代步数的增加而不断减小,实现优化。
完整代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73from numpy import *
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
def plotBestFit(weights):
import matplotlib.pyplot as plt
dataMat,labelMat = loadDataSet()
dataArr = array(dataMat)
n = shape(dataArr)[0]
xcord1 = []; ycord1 = []
xcord2 = []; ycord2 = []
for i in range(n):
if int(labelMat[i]) == 1:
xcord1.append(dataArr[i,1]);ycord1.append(dataArr[i,2])
else:
xcord2.append(dataArr[i,1]);ycord2.append(dataArr[i,2])
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(xcord1,ycord1,s=30,c='red',marker='s')
ax.scatter(xcord2,ycord2,s=30,c='blue')
x = arange(-3.0,3.0,0.1)
y = (-weights[0]-weights[1]*x)/weights[2]
ax.plot(x,y)
plt.xlabel('X1');plt.ylabel('X2');
plt.show()
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
def stocGradAscent1(dataMatrix,classLabels,numIter=150):
m,n = shape(dataMatrix)
weights = ones(n)
for j in range(m):
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19from numpy import *
import logistic
'''
dataArr,labelMat=logistic.loadDataSet()
test_1 = logistic.gradAscent(dataArr,labelMat)
print test_1
'''
# test of gradAscent
'''
dataArr,labelMat=logistic.loadDataSet()
weights = logistic.gradAscent(dataArr,labelMat)
logistic.plotBestFit(weights.getA())
'''
# test of stocGradAscent0
dataArr,labelMat=logistic.loadDataSet()
weights = logistic.stocGradAscent1(array(dataArr),labelMat)
logistic.plotBestFit(weights)
测试结果如下:
未进行优化的结果如图:
进行随机梯度上升优化的结果如图:
在随机梯度上升基础上进行步长优化的结果如图:
可以发现其结果在相同迭代次数的基础上,相比随机梯度上升算法有较大的优化。
算法应用
需要说明的是,Logistic回归是SVM和神经网络的基础。神经网络的单个神经元可以看做一个简化的Logistic回归,并且Sigmoid函数也常作为神经网络的激活函数。
算法小结
Logistic回归目的是寻找一个非线性函数Sigmoid函数的最佳拟合参数,求解过程由最优化算法实现,在优化算法中,梯度上升是较常用的一种方法,并可以利用随机梯度上升进行优化。