回归:假设现有一些数据点,用一条直线对这些点进行拟合(最佳拟合直线),拟合的过程就称作回归。
利用logistic回归进行分类的主要思想是:根据现有数据对分类边界线建立回归公式,以此进行分类
logistic回归主要是进行二分类预测,也即是对于0~1之间的概率值,当概率大于0.5预测为1,小于0.5预测为0.
为了寻找最佳的回归系数 ω \omega ω,这里使用梯度上升法。
梯度上升法基于的思想是:要找到某函数的最大值,最好的方法是沿着该函数的梯度方向探寻。如果梯度记为∇,则函数f(x,y)的梯度由下式表示:
Δ f ( x , y ) = [ ∂ f ( x , y ) ∂ x ∂ f ( x , y ) ∂ y ] \Delta f(x,y) = \left[ \begin{matrix} \frac {\partial f(x,y)}{\partial x} \\ \frac {\partial f(x,y)}{\partial y}\end{matrix} \right] Δf(x,y)=[∂x∂f(x,y)∂y∂f(x,y)]
这个梯度意味着要沿x的方向移动 ∂ f ( x , y ) ∂ y \frac {\partial f(x,y)}{\partial y} ∂y∂f(x,y)
沿y的方向移动 ∂ f ( x , y ) ∂ x \frac {\partial f(x,y)}{\partial x} ∂x∂f(x,y)
其中,函数f (x,y)必须要在待计算的点上有定义并且可微。
梯度上升算法到达每个点后都会重新估计移动的方向。从P0开始,计算完该点的梯度,函数就根据梯度移动到下一点P1。在P1点,梯度再次被重新计算,并沿新的梯度方向移动到P2。如此循环迭代,直到满足停止条件。迭代的过程中,梯度算子总是保证我们能选取到最佳的移动方向。
梯度算子总是指向函数值增长最快的方向。这里所说的是移动方向,而未提到移动量的大小。该量值称为步长,记做α。用向量来表示的话,梯度上升算法的迭代公式如下:
ω : = ω + α Δ ω f ( ω ) \omega := \omega + \alpha \Delta_\omega f(\omega) ω:=ω+αΔωf(ω)
该公式将一直被迭代执行,直至达到某个停止条件为止,比如迭代次数达到某个指定值或算法达到某个可以允许的误差范围。
注:一般我们听到的都是梯度下降法,两着并没有什么区别,只是迭代公式符号发生改变
ω : = ω − α Δ ω f ( ω ) \omega := \omega - \alpha \Delta_\omega f(\omega) ω:=ω−αΔωf(ω)
(1)假设有100个样本点,每个样本有两个特征:x1和x2,此外为方便考虑,额外添加一个x0 = 1,将线性函数 z = ω T x + b z = \omega^Tx+b z=ωTx+b转为 z = ω T x z = \omega^Tx z=ωTx
#梯度上升法更新最优拟合参数
#@dataMatIn:数据集
#@classLabels:数据标签
def gradAscent(dataMatIn,classLabels):
#将数据集列表转为Numpy矩阵
dataMatrix = np.mat(dataMatIn)
#将数据集标签列表转为Numpy矩阵,并转置
labelMat = np.mat(classLabels).transpose()
labelMat = np.array(list(map(float,labelMat)))
#获取数据集矩阵的行数和列数
col,row = np.shape(dataMatrix)
#学习步长
alpha = 0.001
#最大迭代数
maxCycles = 500
#初始化权值参数向量每个维度为1.0
weights = np.ones((row,1))
#循环迭代次数
for k in range(maxCycles):
#求当前的digmoid函数预测概率
h = sigmoid(dataMatrix*weights)
#计算真实类别和预测类别的差值
#对logistic回归函数的对数释然函数的参数项求偏导
error = (labelMat - h)
#更新权值参数
weights = weights + alpha*dataMatrix.transpose()*error
return weights
(2)绘制决策边界
#随机梯度上升算法
def stoGradAscent(dataMatrix,classLabels):
#为方便计算,转为Numpy数组
dataMat = np.array(dataMatrix)
#将数据集标签列表转为Numpy矩阵,并转置
labelMat = np.mat(classLabels).transpose()
labelMat = np.array(list(map(float,labelMat)))
#获取数据集的行和列
col,row = np.shape(dataMat)
#初始化权值向量各个参数为1.0
weights = np.ones(row)
#设置步长为0.01
alpha = 0.01
#循环col次,每次选取数据集一个样本更新参数
for i in range(col):
# 求当前样本的digmoid函数值
h = sigmoid(dataMat[i] + weights)
# 计算当前样本的残差(代替梯度)
error = (labelMat[i] - h)
# 更新权值参数
weights = weights + alpha * dataMat[i] * error
return weights
def classifyVector(inX,weights):
#计算logistic回归预测概率
prob = sigmoid(np.sum(inX*weights))
#大于0.5预测为1
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()
#新建列表存储每个样本的特征向量
lineArr = []
#遍历每个样本的特征
for i in range(21):
#将每个样本的特征存入lineArr列表
lineArr.append(float(currLine[i]))
#将该样本标签存入标签列表
trainingLabels.append(currLine[21])
#将该列表的特征向量添加到数据集列表
trainingSet.append(lineArr)
#调用梯度上升法更新logistic回归的权值参数
trainWeights = stoGradAscent(trainingSet,trainingLabels)
#统计测试数据集预测样本数量和样本总数
errorCount = 0
numTestVec = 0.0
#遍历测试数据集的每个样本
for line in frTest.readlines():
#样本总数加1
numTestVec += 1.0
#对当前行进行处理,分割出各个特征集样本标签
currLine = line.strip().split()
#新建特征向量
lineArr = []
#将各个特征构成特征向量
for i in range(21):
lineArr.append(float(currLine[i]))
#利用分类预测函数对样本进行预测,并于样本标签进行比较
if classifyVector(lineArr,trainWeights) != currLine[21]:
#如果预测错误,错误加1
errorCount += 1
#计算测试集总的预测错误率
errorRate = (float(errorCount)/numTestVec)
print('the error rate of this test is :',errorRate)
return errorRate
#多次测试算法求取误差平均值
def multTest():
#设置测试次数为10次,并统计错误率总和
numTests = 10
errorRateSum = 0.0
for k in range(numTests):
errorRateSum += colicTest()
print('after ',numTests,' iterations the average error rate is : ',errorRateSum/float(numTests))
from sklearn import linear_model
from sklearn import metrics
from sklearn.metrics import accuracy_score
# 加载数据
def loadData(filename):
fr = open(filename)
dataSet = []
Labels = []
for line in fr.readlines():
currLine = line.strip().split('\t')
dataSet.append([float(lineArr) for lineArr in currLine[:-1]])
Labels.append(float(currLine[-1]))
return dataSet,Labels
if __name__ == '__main__':
trainingSet,trainingLabels = loadData('horseColicTraining.txt')
testSet,testLabels = loadData('horseColicTest.txt')
#训练一个logistic回归模型,设置迭代次数为1000(默认为100,会导致结果不收敛,从而触发警告)
logistic_model = linear_model.LogisticRegression(max_iter=1000)
logistic_model = logistic_model.fit(trainingSet,trainingLabels)
predicted=logistic_model.predict(testSet)
deathCount = 0
for i in predicted:
if i == 0:
deathCount += 1
deathRate = float(deathCount)/len(predicted)
score = logistic_model.score(testSet,testLabels)
print('The accuracy of logistic is :',score)
print('the death rate of this test is :', deathRate)