训练集D 样本{yi;xi} 其中yi取值为0或1 xi=(xi1,xi2....xin)
梯度上升递推式:
利用矩阵运算,同时对于参数进行变更,即对样本空间进行并行计算。
将样本x 类别信息y以及 待求参数表示成矩阵:
计算A以及误差E,利用矩阵运算,同时进行所有样本的计算
参数0的迭代式:
参数j的迭代式:
总体参数的迭代式:
即:
g()取Sigmoid函数。
给定一组二维空间中的点以及相应类别,构建LR最优分类器。
样本实例如下所示:
读取数据,转换为样本矩阵X以及类别向量Y
def loadDataSet():
dataMat = []; labelMat = []
fr = open('testSet.txt')
for line in fr.readlines():
lineArr = line.strip().split()
#特征向量矩阵第一列添加1 wx+b=wx+b*x0=W*X 即把1当成x向量第一维 b看成参数W的某一维 便于直接进行矩阵运算
dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])])
#转换类别向量
labelMat.append(int(lineArr[2]))
return dataMat,labelMat
函数返回的是样本以及类别向量,以数组形式返回。
定义Sigmoid函数:
def sigmoid(inX):
return 1.0/(1+exp(-inX))
利用梯度上升,对于参数向量进行整体迭代求解:
def gradAscent(dataMatIn, classLabels):
#样本数组转换为矩阵
dataMatrix = mat(dataMatIn) #convert to NumPy matrix
#类别数组转换为列向量
labelMat = mat(classLabels).transpose() #convert to NumPy matrix
#样本数目 特征数目
m,n = shape(dataMatrix)
#学习步长
alpha = 0.001
#最大迭代次数
maxCycles = 500
#初始权重
weights = ones((n,1))
for k in range(maxCycles): #heavy on matrix operations
h = sigmoid(dataMatrix*weights) #matrix mult
error = (labelMat - h) #vector subtraction
weights = weights + alpha * dataMatrix.transpose()* error #matrix mult
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='green')
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()
注意调用函数时:logRegres.plotBestFit(w.getA()) getA()将一个矩阵转换为一个数组,结果如下:
以上梯度上升每进行一次迭代都要计算所有样本,计算量较大。
优化梯度上升算法,每次迭代只利用一个样本值来更新回归系数,在线式学习,增量式学习。
def stocGradAscent0(dataMatrix, classLabels):
#样本总数 特征属性总数
m,n = shape(dataMatrix)
#学习步长
alpha = 0.01
#初始权重
weights = ones(n) #initialize to all ones
for i in range(m):
h = sigmoid(sum(dataMatrix[i]*weights))
error = classLabels[i] - h
weights = weights + alpha * error * dataMatrix[i]
return weights
测试如下所示:
import logRegres
d,l = logRegres.loadDataSet()
from numpy import *
w = logRegres.stocGradAscent0(array(d),l)
logRegres.plotBestFit(w)
随机梯度下降算法迭代次数少,分类效果稍差。因为数据集并不是线性可分的,因此存在一些数据,会造成回归系统剧烈变化
代码如下:
def stocGradAscent1(dataMatrix, classLabels, numIter=150):
m,n = shape(dataMatrix)
weights = ones(n) #initialize to all ones
#控制迭代次数
for j in range(numIter):
dataIndex = range(m)
for i in range(m):
#学习步长逐渐减小,但不为零
alpha = 4/(1.0+j+i)+0.0001 #apha decreases with iteration, does not
#随机选择样本来进行训练
randIndex = int(random.uniform(0,len(dataIndex)))#go to 0 because of the constant
h = sigmoid(sum(dataMatrix[randIndex]*weights))
error = classLabels[randIndex] - h
weights = weights + alpha * error * dataMatrix[randIndex]
del(dataIndex[randIndex])
return weights
1.增加迭代次数控制
2.每次随机选择样本来进行回归系数的更新,避免周期性波动
3.学习步长,随迭代次数非严格减小,减小高频波动
测试结果:分别迭代150 300 500次结果如下:
样本数据格式如下所示:
前20列为特征 最后一列为类别信息,给定一个新样本,通过LR来判断其类别情况,并统计错误率。
已知回归系数和待分类向量,判断类别信息:
def classifyVector(inX, weights):
#计算预测值
prob = sigmoid(sum(inX*weights))
if prob > 0.5: return 1.0
else: return 0.0
根据训练集训练回归系数,根据测试集来测试LR分类错误率
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, 1000)
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():
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)))
结果如下: 对于每次随机梯度上升迭代次数分别为150 300次结果
可知,适当增加训练次数能够减少错误率
总结:
LR是一种分类学习方法 通过Sigmoid以及线性函数实现样本空间到{0,1}的映射,最优化可以通过梯度上升来实现求解。