1.这种回归算法的特点:
我们的思路是这样的,假设有这么个函数,对于输入的参数x,f(x)可以均匀的分布到(0,1)之间,且p(y>yi)=p(y<yi) ,也就是说可以通过跟某个值的比较而得到二元值0或者1,这样分类问题就转换成一个数学函数的求值,然后比较的过程。类似于一个圆圈从中间劈开,得到a,b两个区域,落在a区域的记为1,落在b区域的记作0。说白了就是种函数映射。那问题来了?如何选取函数,哪个或者哪类函数能够胜任?
一般来说,阶跃函数是我们需要的。 阶跃函数是指实数域上某个函数可以用半开区间上的指示函数的有限次线性组合来表示,是有限段分段常数函数的组合。
说白了,就是存在从0到1的跳变,然后某个范围是0,某个范围是1。我们选用的是比较平滑的自增删数Sigmoid函数,在生物课本上研究生物圈的时候,应该见过。
好,现在我们有了个好函数,如何处理我们的分类问题呢?我们可以这样做,取特征值然后乘以回归系数,然后取和,得到一个值,代入Sigmoid函数,得到一个函数值,然后跟0.5 比较,如果大于,记为1,小于记为0,这样就完成的分类。
看上去好像也不是很复杂,是吧。但是这里有个问题,如何选取最佳回归系数,让预测值尽量接近真实值,然后做出更加精确的分类??我们转换为数学问题,记X为特征向量,注意为了方便计算,也为了最后数据分类的正确性,我们记x0=1.0 (也是向量),其它特征看作x1 x2 ...xn.
这样就转换成,将这个代入函数,就是在已知X样本的条件下,我们假设样本元素之间是独立的,计算概率为
,对应的参数θ相对于样本集的似然函数
实际上就是使得似然函数最大值的参数的取值(因为不管是取值为0,或者1,都是趋向于最大值,函数本身是单调递增的,值越大,越精确)。
为了简化问题,因为f(x)和ln(f(x))在此问题取到的最大值的点相同,转换下:
我们知道,求最大值一般都会涉及到导数,但是直接求导数某些情况下是行不通的,那可以使用迭代的方式,不断逼近最大值。这就涉及到梯度上升算法。梯度是个向量,用来表示一个函数在该点的方向导数取得最大值,在该点沿着梯度方向函数变化的最快,变化率最大(为该梯度的模)。
(步长,梯度)
然后对参数w求偏导,得到梯度为 (证明过程略过),代入上面得到根据梯度计算权值的迭代公式。
2.代码实现
from numpy import * #预处理数据 def loadDataSet(): #创建两个列表 dataMat=[];labelMat=[] #打开文本数据集 fr=open('/python/machinelearninginaction/Ch05/testSet.txt') #遍历文本的每一行 for line in fr.readlines(): #对当前行去除首尾空格,并按空格进行分离 lineArr=line.strip().split() #将每一行的两个特征x1,x2,加上x0=1,组成列表并添加到数据集列表中,不是很明白这里为啥增加x0=1, # 而不是把读入的两列值看作x0 x1 呢?难道输入值必须是 z=w(T)x+b ? 我知道的,是为了获取下面图中的那条 #最佳分类线,假设为w0x0+w1x1=0 sigmoid(0)=0.5 =>x1=-w0x0/w1 这样就只能是f(x)=kx,不符合实际情况 #实际应该是f(x)=kx+b,一个通用一次线性函数,=>w0+w1x1+w2x2=0=>取x0=1,z=w0x0+w1x1+w2x2 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)) #梯度上升法更新最优拟合参数 #@dataMatIn:数据集 #@classLabels:数据标签 def gradAscent(dataMatIn,classLabels): #将数据集列表转为Numpy矩阵 dataMatrix=mat(dataMatIn) #将数据集标签列表转为Numpy矩阵,并转置 labelMat=mat(classLabels).transpose() #获取数据集矩阵的行数和列数 m,n=shape(dataMatIn) #学习步长 alpha=0.001 #最大迭代次数 maxCycles=500 #初始化权值参数向量每个维度均为1.0 weights=ones((n,1)) #循环迭代次数 for k in range(maxCycles): #求当前的sigmoid函数预测概率 h=sigmoid(dataMatrix*weights) #*********************************************** #此处计算真实类别和预测类别的差值 #对logistic回归函数的对数释然函数的参数项求偏导 error=(labelMat-h) #更新权值参数 weights=weights+alpha*dataMatrix.transpose()*error #*********************************************** return weights def plotBestFit(wei): import matplotlib.pyplot as plt weights = wei.getA() 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('Logistic回归') 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() dataMatIn,classLabels=loadDataSet() weight=gradAscent(dataMatIn,classLabels) print('weight=\n',weight) plotBestFit(weight)
3.画图
4.改进
from numpy import * #预处理数据 def loadDataSet(): #创建两个列表 dataMat=[];labelMat=[] #打开文本数据集 fr=open('/python/machinelearninginaction/Ch05/testSet.txt') #遍历文本的每一行 for line in fr.readlines(): #对当前行去除首尾空格,并按空格进行分离 lineArr=line.strip().split() #将每一行的两个特征x1,x2,加上x0=1,组成列表并添加到数据集列表中,不是很明白这里为啥增加x0=1, # 而不是把读入的两列值看作x0 x1 呢?难道输入值必须是 z=w(T)x+b ? 我知道的,是为了获取下面图中的那条 #最佳分类线,假设为w0x0+w1x1=0 sigmoid(0)=0.5 =>x1=-w0x0/w1 这样就只能是f(x)=kx,不符合实际情况 #实际应该是f(x)=kx+b,一个通用一次线性函数,=>w0+w1x1+w2x2=0=>取x0=1,z=w0x0+w1x1+w2x2 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)) #梯度上升法更新最优拟合参数 #@dataMatIn:数据集 #@classLabels:数据标签 def gradAscent(dataMatIn,classLabels): #将数据集列表转为Numpy矩阵 dataMatrix=mat(dataMatIn) #将数据集标签列表转为Numpy矩阵,并转置 labelMat=mat(classLabels).transpose() #获取数据集矩阵的行数和列数 m,n=shape(dataMatIn) #学习步长 alpha=0.001 #最大迭代次数 maxCycles=500 #初始化权值参数向量每个维度均为1.0 weights=ones((n,1)) #循环迭代次数 for k in range(maxCycles): #求当前的sigmoid函数预测概率 h=sigmoid(dataMatrix*weights) #*********************************************** #此处计算真实类别和预测类别的差值 #对logistic回归函数的对数释然函数的参数项求偏导 error=(labelMat-h) #更新权值参数 weights=weights+alpha*dataMatrix.transpose()*error #*********************************************** return weights #减少迭代次数,避免每次对整个数据集迭代 #@dataMatIn:数据集 #@classLabels:数据标签 #@numIter: 迭代次数 def stocGradAscent(dataMatIn,classLabels,numIter=150): #将数据集列表转为Numpy矩阵 #dataMatrix=mat(dataMatIn) #将数据集标签列表转为Numpy矩阵,并转置 #labelMat=mat(classLabels).transpose() #获取数据集矩阵的行数和列数 m,n=shape(dataMatIn) #学习步长 #alpha=0.001 alpha=0.01 #最大迭代次数 #maxCycles=500 #初始化权值参数向量每个维度均为1.0 weights=ones(n) for i in range(numIter): dataIndex=list(range(m)) #每次取样本中的一个 for j in range(m): alpha=4.0/(i+j+1)+0.01 k=int(random.uniform(0,len(dataIndex))) # 求当前的sigmoid函数预测概率 h = sigmoid(sum(dataMatIn[k] * weights)) # *********************************************** # 此处计算真实类别和预测类别的差值 error = (classLabels[k] - h) # 更新权值参数 weights = weights + alpha * dataMatIn[k] * error del(dataIndex[k]) # *********************************************** return weights def plotBestFit(wei): import matplotlib.pyplot as plt #weights = wei.getA() weights=wei 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('Logistic回归') 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() dataMatIn,classLabels=loadDataSet() #weight=gradAscent(dataMatIn,classLabels) weight=stocGradAscent(array(dataMatIn),classLabels) print('weight=\n',weight) plotBestFit(weight)
![](https://i-blog.csdnimg.cn/blog_migrate/7b7d625b158f508abbfd2b3f401a7e75.png)