logistic是一种广义的线性回归分析模型,用于建立自变量与因变量之间的关系模型。不同于线性回归、线性模型,logistic回归在线性模型的基础上嵌套一层非线性函数,使得模型可以拟合曲线(面)函数,同时将输出结果范围控制在[0, 1]中使得输出结果直接对应输出类别的概率。本此实验采用sigmoid函数实现logistic回归。
s i g m o i d ( z ) = 1 1 + e − z sigmoid(z)=\frac{1}{1+e^{-z}} sigmoid(z)=1+e−z1
本次实验解决二维空间的二分类问题,先准备若干个二维点与对应类别。存放于testSet.txt中。
此次实验需要numpy数学库和可视化展示所需的matplotlib库。
from numpy import *
import matplotlib.pyplot as plt
从testSet.txt中读取所有二维点
def loadDataSet():
dataMat = []
labelMat = []
fr = open('testSet.txt')
for line in fr.readlines():
# 矩阵的格式【标签,X1,X2】
lineArr = line.strip().split()
#插入X1,X2,以及初始化的回归系数(权重),全部设为1.0
dataMat.append([1.0,float(lineArr[0]),float(lineArr[1])])
#插入标签,
#必须转换成int类型,因为只有两类
labelMat.append(int(lineArr[2]))
return dataMat,labelMat
# 使用sigmoid函数进行分类
def sigmoid(inX):
return 1.0/(1+exp(-inX))
本次实验采用梯度上升算法进行反向传播更新权重。
#使用梯度上升算法进行优化,找到最佳优化系数
#dataMatIn是训练集,三维矩阵,(-0.017612 14.053064 0)
#classLabels是类别标签,数值型行向量,需要转置为列向量,取值是0,1
def gradAscent(dataMatIn,classLabels):
dataMatrix = mat(dataMatIn) #转换为Numpy矩阵数据类型
labelMat = mat(classLabels).transpose() #转置矩阵,便于加权相乘
m,n = shape(dataMatrix) #得到矩阵的行列数,便于设定权重向量的维度
alpha = 0.001
maxCycles = 500
weights = ones((n,1)) #返回一个被1填满的 n * 1 矩阵,作为初始化权重
for k in range(maxCycles):
h = sigmoid(dataMatrix*weights)
erro = (labelMat - h) #labelMat是使用当前回归系数得到的的标签,labelMat是训练集的标签,取值是0,1
weights = weights + alpha * dataMatrix.transpose( ) * erro #根据使用当前权重计算的值与初始值的误差,更改weight,
#按照误差的方向调整回归系数
return weights
根据训练好的权重和已有数据点绘制图线。
def plotBestFit(wei):
weights = wei.getA()
dataMat,labelMat = loadDataSet()
dataArr = array(dataMat)
n = shape(dataMat)[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') #scatter散开
ax.scatter(xcord2,ycord2,s=30,c='green')
x = arange(-3.0,3.0,1)
y = (-weights[0]-weights[1]*x)/weights[2]
ax.plot(x,y)
plt.xlabel('x1')
plt.ylabel('x2')
plt.show()
将以上代码整合可得
class func:
def loadDataSet(self):
dataMat = []
labelMat = []
fr = open('testSet.txt')
for line in fr.readlines():
# 矩阵的格式【标签,X1,X2】
lineArr = line.strip().split()
#插入X1,X2,以及初始化的回归系数(权重),全部设为1.0
dataMat.append([1.0,float(lineArr[0]),float(lineArr[1])])
#插入标签,
#必须转换成int类型,因为只有两类
labelMat.append(int(lineArr[2]))
return dataMat,labelMat
# 使用sigmoid函数进行分类
def sigmoid(self,inX):
return 1.0/(1+exp(-inX))
#使用梯度上升算法进行优化,找到最佳优化系数
#dataMatIn是训练集,三维矩阵,(-0.017612 14.053064 0)
#classLabels是类别标签,数值型行向量,需要转置为列向量,取值是0,1
def gradAscent(self,dataMatIn,classLabels):
dataMatrix = mat(dataMatIn) #转换为Numpy矩阵数据类型
labelMat = mat(classLabels).transpose() #转置矩阵,便于加权相乘
m,n = shape(dataMatrix) #得到矩阵的行列数,便于设定权重向量的维度
alpha = 0.001
maxCycles = 500
weights = ones((n,1)) #返回一个被1填满的 n * 1 矩阵,作为初始化权重
for k in range(maxCycles):
h = self.sigmoid(dataMatrix*weights)
erro = (labelMat - h) #labelMat是使用当前回归系数得到的的标签,labelMat是训练集的标签,取值是0,1
weights = weights + alpha * dataMatrix.transpose( ) * erro #根据使用当前权重计算的值与初始值的误差,更改weight,
#按照误差的方向调整回归系数
return weights
def plotBestFit(self,wei):
weights = wei.getA()
dataMat,labelMat = self.loadDataSet()
dataArr = array(dataMat)
n = shape(dataMat)[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') #scatter散开
ax.scatter(xcord2,ycord2,s=30,c='green')
x = arange(-3.0,3.0,1)
y = (-weights[0]-weights[1]*x)/weights[2]
ax.plot(x,y)
plt.xlabel('x1')
plt.ylabel('x2')
plt.show()
if __name__=="__main__":
logRegres = func()
dataArr,labelMat = logRegres.loadDataSet()
weights = logRegres.gradAscent(dataArr,labelMat)
logRegres.plotBestFit(weights)
使用logistic回归具有无需假定分布的好处。[0,1]范围的输出可以视为概率用于扩展,引入独热编码即可解决多分类问题。同时可直接应用现有数值优化算法(如牛顿法)求取最优解,具有快速、高效的特点。