Logistic回归
优点:计算代价不高,易于理解和实现 缺点:容易欠拟合,分类精度可能不高 适用数据类型:数值型和标称型数据
??这是最优化算法。主要思想是:根据现有的数据对分类边界线建立回归公式,以此进行分类。“ 回归 ”一词源于最佳拟合,表示要找到最佳拟合参数集。训练分类器识的做法就是寻找最佳拟合参数。
Logistic回归的一般过程
- 收集数据:采用任意方法收集数据
- 准备数据:由于需要进行距离计算,因此要求数据类型为数值型。另外,结构化数据格式则最佳
- 分析数据:采用任意方法对数据进行分析
- 训练算法:计算不同独立特征的条件概率
- 测试算法:一旦训练步骤完成,分类将会很快
- 使用算法:首先需要输入一些数据,并将其转化成对应的结构化数值;接着,基于训练好的的回归系数就可以对这些数值进行简单的回归计算,判定他们属于哪个类别;之后就可以在输出的类别上做出一些其他的分析工作。
基于Logistic回归和Sigmoid函数的分类
??我们想要的函数,能接受所有的输入然后预测出类别。Sigmoid函数具有输出0或1的这种性质,而且在数学上容易处理。因此为了实现Logistic回归分类器,我们可以在每一个特征上都乘以一个回归系统,然后将所有的结果值相加,将这个总和代入Sigmoid函数中,进而得到一个范围在0~1之间的数值。Sigmoid函数定义:
σ
(
z
)
=
1
1
+
e
?
z
\sigma(z)=\dfrac{1}{1+e^{-z}}
σ(z)=1+e?z1?
任何大于0.5的数据被分入1类,小于0.5的数据被归入0类。所以Logistic回归也可以看成是一种概率估计。
基于最优化方法的最佳回归系数确定
??Sigmoid函数的输入记为z,公式为:
z
=
w
0
x
0
+
w
1
x
1
+
w
2
x
2
+
.
.
.
+
w
n
x
n
z=w_0x_0+w_1x_1+w_2x_2+...+w_nx_n
z=w0?x0?+w1?x1?+w2?x2?+...+wn?xn?
上述公式可简化为
z
=
W
T
x
z=W^Tx
z=WTx,它表示数值向量对应元素相乘然后全部相加起来即得到
z
z
z值。其中的向量
x
x
x是分类器的输入数据,向量
w
w
w是要求的最佳参数(系数),使分类器尽可能的精确。
梯度上升法
??思想:要找到某函数的最大值,最好的方法是沿着该函数的梯度方向探寻。函数
f
(
x
,
y
)
f(x,y)
f(x,y)的表示:
?
f
(
x
,
y
)
=
(
?
f
(
x
,
y
)
?
x
?
f
(
x
,
y
)
?
y
)
\nabla f(x,y)= \begin{pmatrix} \dfrac{\partial f(x,y)}{\partial x} \\ \dfrac{\partial f(x,y)}{\partial y}\end{pmatrix}
?f(x,y)=?????x?f(x,y)??y?f(x,y)??????
要记住这些符号的含义:这个梯度意味着要沿
x
x
x的方向移动
?
f
(
x
,
y
)
?
x
\dfrac{\partial f(x,y)}{\partial x}
?x?f(x,y)?,沿
y
y
y的方向移动
?
f
(
x
,
y
)
?
y
\dfrac{\partial f(x,y)}{\partial y}
?y?f(x,y)?。其中,函数
f
(
x
,
y
)
f(x,y)
f(x,y)必须要在待计算的点上有定义并且可微。 ??梯度算子总是指向函数值增长最快的方向。这里说的是移动方向,而没有提到移动量的大小。该量值称为步长,记作
a
a
a。用向量来表示梯度上升算法:
w
:
=
w
+
a
?
w
f
(
w
)
w:=w+a\nabla_w f(w)
w:=w+a?w?f(w)
??该公式将一直被迭代执行,直到达到某一停止条件为止。
梯度下降算法
??我们最经常听到梯度下降算法,它与梯度上升算法是一样的,只是公式中加法变成减法。因此,公式为:
w
:
=
w
?
a
?
w
f
(
w
)
w:=w-a\nabla_w f(w)
w:=w?a?w?f(w) ??梯度上升算法用来求函数的最大值,而梯度下降算法用来求函数的最小值。
训练算法:使用梯度上升找到最佳参数
??通过梯度上升找到最佳参数,也就是拟合出Logistic回归模型的最佳参数。
分析数据:画出决策边界
??从上面已经解出了一组回归系数,他确定了不同类别数据之间的分割线。
训练算法:随机梯度上升
??梯度上升算法在每次更新回归系数的时候需要遍历整个数据集,该方法在处理100个左右的数据的时候还可以,但若有数十亿样本和成千上万的特征,该方法复杂度就太高了,一种改进的方法是一次仅使用一个样本点来更新回归系数,该方法称为随机梯度上升算法。由于可以在新样本到来时对分类器进行增量式更新,因而随机梯度上升算法是一个在线学习算法。
5、完整示例代码
from numpy import mat, shape, ones
import numpy as np
import matplotlib.pyplot as plt
from numpy.core.records import array
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.0 + np.exp(-inX))
def gradAscent(dataMatIn, classLabels):
dataMatrix = mat(dataMatIn)
lableMat = mat(classLabels).transpose()
m, n = shape(dataMatIn)
alpha = 0.001
maxCycles = 500
weights = ones((n, 1))
for k in range(maxCycles):
h = sigmoid(dataMatrix*weights)
error = (lableMat - h)
weights = weights + alpha * dataMatrix.transpose() * error
return weights
def plotBestFit(weights):
dataMat, labelMat = loadDataSet()
dataArr = np.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='green')
x = np.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)
dataMatrix = np.array(dataMatrix)
alpha = 0.01
weights = np.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)
dataMatrix = np.array(dataMatrix)
weights = np.ones(n)
for j in range(numIter):
dataIndex=list(range(m))
for i in range(m):
alpha = 4/(1.0+j+i)+0.01
randIndex=int(np.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
dataMatIn, classLabels = loadDataSet()
weights = stocGradAscent1(dataMatIn, classLabels)
weights = stocGradAscent0(dataMatIn, classLabels)
plotBestFit(weights)
梯
度
上
升
算
法
结
果
梯度上升算法结果
梯度上升算法结果
随
机
梯
度
上
升
算
法
结
果
随机梯度上升算法结果
随机梯度上升算法结果
改
进
随
机
梯
度
上
升
算
法
结
果
改进随机梯度上升算法结果
改进随机梯度上升算法结果
??从结果上看,梯度上升算法比改进前的梯度上升算法要好。因为改进前的梯度上升算法分类器错分了近一半的样本,但是直接看结果是不公平的。梯度上升算法在整个数据集上迭代了500次,才将结果收敛达到了稳定值,而改进前的梯度上升算法在整个数据集上迭代了200次达到了最终的效果。 ??改进后的程序,通过随机选取样本来更新回归系数,这种方法将减少周期性的波动,而且增加了一个迭代次数作为第三个参数。
示例从疝气病症预测病马的死亡率
使用Logistic回归估计马疝病的死亡率
- 收集数据:给定数据文件
- 准备数据:用python解析文本文件并填充缺失值
- 分析数据:可视化并观察数据
- 训练算法:使用优化算法,找到最佳的系数
- 测试算法:为了量化回归的效果,需要观察错误率。根据错误率决定是否回退到训练阶段,通过改变迭代的次数与步长等参数来得到更好的回归系数
- 使用算法:实现一个简单的命令行程序来收集马的症状并输出预测的结果
1、准备数据:处理数据中的缺失值
??解决缺失数据的一些可选办法:
- 使用可用特征的均值来填补缺失值
- 使用特殊值来填补缺失值,如-1
- 忽略有缺失值的样本
- 使用相似样本的均值添补缺失值
- 使用另外的机器学习算法预测缺失值
??在预处理阶段需要做的事:
- 所有的缺失值必须有一个实数来替换,因为numpy数据类型不允许包含缺失值
- 若在测试数据中发现了一条数据类别的标签已经有缺失,则最简单的方式是直接丢弃该数据
2、测试算法:用Logistic回归进行分类
??将数据上的每一个特征向量乘以最优化方法得来的回归系数,再将该乘积结果求和,最后输入到Sigmoid函数中即可
3、完整示例代码
import numpy as np
from numpy import *
def classifyVector(inX,weights):
prob=sigmoid(sum(inX*weights))
if prob>0.5: return 1.0
else: return 0.0
def colicTset():
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
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():
numTest=10
errorSum=0.0
for k in range(numTest):
errorSum+=colicTset()
print("After %d iterations the average error rate is: %f"%(numTest,errorSum/float(numTest)))
def sigmoid(inX):
if inX>=0:
return 1.0/(1+np.exp(-inX))
else:
return np.exp(inX)/(1+np.exp(inX))
def stocGradAscent1(dataMatrix, classLabels,numIter=150):
m, n = shape(dataMatrix)
dataMatrix = np.array(dataMatrix)
weights = np.ones(n)
for j in range(numIter):
dataIndex=list(range(m))
for i in range(m):
alpha = 4/(1.0+j+i)+0.01
randIndex=int(np.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
multiTest()
小结
??Logistic回归的目的是寻找一个非线性的函数Sigmoid的最佳拟合参数,求解过程可以是最优化算法来完成。在最优化算法中,最常用的是梯度上升算法,而梯度上升算法又可以简化为随机梯度上升算法。 ??随机梯度上升算法与梯度上升算法效果相当,但是占用资源较少。此外随机梯度上升是一个线性算法,它可以在新数据到来时就完成参数更新,而不需要重新读取整个数据集来进行批处理运算。 ??机器学习的一个重要问题就是处理缺失数据,解决的方法取决于实际应用的需求。
由于代码中horseColicTraining.txt与horseColicTest.txt文件数据较多,请读者自行查找数据
|