前言


logistic回归的主要思想:根据现有数据对分类边界建立回归公式,以此进行分类
所谓logistic,无非就是True or False两种判断,表明了这其实是一个二分类问题
我们又知道回归就是对一些数据点拟合成线性函数,但是线性函数的值域是无穷的
所以logistic和回归加在一起,就是要把取值范围从无穷映射到(0,1)上,使之成为一个二分类器
所以本文会介绍怎么拟合一个回归函数,然后再把它作为自变量输入丢进一个阶跃函数,然后输出一个(0,1)的二值结果
这就是所谓的logistic回归

本文的参考书是《机器学习实战》

sigmoid函数


由前言中知道,我们需要一个阶跃函数,不管接受什么输入,输出的都是0或1
sigmoid函数刚好满足这样的特性:

它的图形如下:

当z=0时,函数值为0.5。
把自变量带入函数会得到一个0~1之间的数值,这时就可以把大于0.5的数据分为1类,小于0.5的归为0类。
所以logistic回归可以被看成是一种概率估计。
这样就完成了把无穷取值范围映射到0和1的使命。
接下来需要做的就是就是对数据点进行回归,使回归得到的结果成为sigmoid函数的输入

最佳回归系数


线性回归的形式是:

其中W就是回归系数向量,向量的每个元素对应数据的一个维度也就是一种特征

现在的任务就是确定最佳回归系数,常用的方法有最小二乘法、梯度上升法等最优化方法。

本文主要是使用梯度上升法作为讨论的基础

梯度上升法

梯度上升基于的思想是:要找函数的最大值,最好的方法是沿着该函数的梯度方向探寻,因为梯度总是指向函数增长最快的方向
有了方向,那么还要有步长才能朝着最优值移动,这个步长可以自己指定,这里设步长为alpha,那么算法的迭代公式为:

顺便提一下,相应的有个叫梯度下降的算法,用于求函数的最小值,只用把中间的加号变成减号就行了
梯度上升的伪代码如下:
  1. 每个回归系数初始化为1
  2. 重复R次:
  3. 计算整个数据集的梯度
  4. 使用 alpha * gradient 更新回归系数向量
  5. 返回回归系数

代码实现如下:
  1. # 载入测试数据,返回测试数据集和类别标签
  2. def loadDataSet():
  3. dataMat = []
  4. labelMat = []
  5. fr = open(r'E:\ml\machinelearninginaction\Ch05\testSet.txt')
  6. dataFromFile = fr.readlines()
  7. print len(dataFromFile)
  8. for line in dataFromFile:
  9. lineArr = line.strip().split()
  10. dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])])
  11. labelMat.append(int(lineArr[2]))
  12. return dataMat, labelMat
  13. # sigmoid 函数
  14. def sigmoid(inX):
  15. return 1.0/(1+exp(-inX))
  16. # =====================================
  17. # 梯度上升算法
  18. # 输入:
  19. # dataMatIn: 2维数组,每列代表一种特征
  20. # classLabels: 类别标签
  21. # 返回:逻辑回归参数
  22. # =====================================
  23. def gradAscent(dataMatIn, classLabels):
  24. dataMat = mat(dataMatIn)# 装换成numpy矩阵
  25. labelMat = mat(classLabels).transpose()# 转置
  26. m, n = shape(dataMat)
  27. weights = ones((n, 1))# 初始化权重都为1
  28. alpha = 0.001
  29. maxCycles = 500# 迭代次数
  30. for i in range(maxCycles):
  31. # 以下三行代码是梯度上升算法的具体实现
  32. h = sigmoid(dataMat * weights)# 矩阵乘法
  33. error = (labelMat - h)
  34. weights = weights + alpha * dataMat.transpose() * error
  35. return weights
关于代码有两点需要指出,第10行中loadData函数在特征列加了一列全是1的特征。
21~23行代码是梯度上升的具体实现,由上面提到的迭代公式到这里的实现需要一些数学推导,大概来说如下:


本文的数据集用的是《机器学习实战》的testSet.txt数据集,概览图如下:

导入数据集到上面的函数得到如下结果:

这就是回归系数

画出决策函数

为了使优化过程便于理解,我们可以把这个数据集已经刚才已经得到的回归线可视化
代码如下:
  1. # 画出数据集合logistic回归最佳拟合直线的函数
  2. # 输入wei是系数向量
  3. def plotBestFit(wei):
  4. import matplotlib.pyplot as plt
  5. weight = wei.getA() # 矩阵转换成数组
  6. dataMat, labelMat = loadDataSet()
  7. dataArray = array(dataMat)
  8. n = shape(dataArray)[0] # 获得数组的行数
  9. xcord1 = []
  10. ycord1 = []
  11. xcord2 = []
  12. ycord2 = []
  13. for i in range(n):
  14. if labelMat[i] == 1:
  15. xcord1.append(dataArray[i, 1])
  16. ycord1.append(dataArray[i, 2])
  17. else:
  18. xcord2.append(dataArray[i, 1])
  19. ycord2.append(dataArray[i, 2])
  20. fig = plt.figure()
  21. ax = fig.add_subplot(111)
  22. ax.scatter(xcord1, ycord1, s=30, c='red', marker='s')
  23. ax.scatter(xcord2, ycord2, s=30, c='green')
  24. x = arange(-3.0, 3.0, 0.1)
  25. y = (-weight[0] - weight[1] * x) / weight[2]
  26. ax.plot(x, y)
  27. plt.show()
这就是使用梯度上升500次得到的结果,效果还不错

随机梯度上升

从上面的代码可以看出梯度上升法每次更新回归系数的时候都要遍历整个数据集,计算复杂度太高
一种改进的方法是一次只用一个样本点来更新回归系数,这种方法叫做随机梯度上升算法
这样的话,每输入一个新的样本就可以对分类器进行一次更新,这种方式叫做增量式更新,所以这个算法是一个在线学习算法
与在线学习算法相对应的,一次处理所有数据被称作“批处理

改进后代码如下:
  1. # =========================================
  2. # 随机梯度上升算法
  3. # =========================================
  4. def stoGradAsent0(dataMatrix, classLabels):
  5. m, n = shape(dataMatrix)
  6. weights = ones(n)
  7. alpha = 0.001
  8. for i in range(m):
  9. h = sigmoid(sum(dataMatrix[i] * weights))
  10. err = h - classLabels[i]
  11. weights = weights + alpha * err * dataMatrix[i]
  12. return weights
用下面的代码调用上面的函数:
  1. data, label = loadDataSet()
  2. wei = stocGradAscent0(array(data), label)
  3. plotBestFit(wei)
得到如下分类结果:

可以看到这个分类效果没有之前的分类效果好。但是之前的效果是迭代500次才得到的,所以不具有可比性。

改进的随机梯度上升

  1. def stocGradAscent1(dataMatrix, classLabels, numIter=150):
  2. m,n = shape(dataMatrix)
  3. weights = ones(n)
  4. for j in range(numIter):
  5. dataIndex = range(m)
  6. for i in range(m):
  7. # alpha随着迭代次数减小,但是有常数项保证永远不会小到0
  8. alpha = 4/(1.0+j+i)+0.0001
  9. # 随机选取样本来更新回归系数
  10. randIndex = int(random.uniform(0,len(dataIndex)))
  11. h = sigmoid(sum(dataMatrix[randIndex]*weights))
  12. error = classLabels[randIndex] - h
  13. weights = weights + alpha * error * dataMatrix[randIndex]
  14. del(dataIndex[randIndex])
  15. return weights
从代码中我们可以看到主要做出了两个改进:
  1. 第八行代码表示alpha随着迭代次数减小,这是为了缓解回归系数的波动,尽快达到收敛状态(收敛是判断一个优化算法是否可靠的重要方法)。并且alpha有常数项保证永远不会小到0
  2. 第十行表示随机选取样本来更新回归系数,这样是为了减少周期波动
对数据集作20次遍历stocGradAscent1(array(data), label, 20)得到的分类效果如下:

很明显效果比没有改进前的随机梯度上升算法要好多了。

例子:从疝气病预测病马的死亡率


缺失值处理

在正式开始这个例子之前我们想先讨论一下数据中的缺失值处理
因为即将用到这个数据集的原始数据集是有缺失值的,而且缺失值的处理的数据的预处理中非常重要
常用的缺失值处理方法:
  • 使用可用特征的均值填补
  • 使用特殊值来填补缺失值,比如0或-1
  • 忽略有缺失值的样本
  • 使用其他机器学习算法来预测缺失值
  • 使用相似样本对应特征的均值俩填补
以下两种情况的值缺失处理方法是不同的
  1. 特征缺失:可以丢弃此样本;否则的话,由于numpy不支持包含缺失值,所以必须要填补上
  2. 标签缺失:基本上只能直接丢弃,因为和特征值不同,它很难使用某个合适值来替换

用logistic回归进行分类

  1. # 用于为每个输入样本分类
  2. # inX为待分类的样本的特征值
  3. # weights 为训练好的权重
  4. def classifyVector(inX, weights):
  5. prob = sigmoid(sum(inX * weights))
  6. if prob > 0.5:
  7. return 1
  8. else:
  9. return 0
  10. def colicTest():
  11. frTrain = open(r'E:\ml\machinelearninginaction\Ch05\horseColicTraining.txt')
  12. frTest = open(r'E:\ml\machinelearninginaction\Ch05\horseColicTest.txt')
  13. trainData = []
  14. trainLabels = []
  15. for line in frTrain.readlines():
  16. currLine = line.strip().split('\t')
  17. lineArr = []
  18. for i in range(21):#这个数据集有21个特征
  19. lineArr.append(float(currLine[i]))
  20. trainData.append(lineArr)
  21. trainLabels.append(float(currLine[21]))
  22. # 用训练集作500次迭代得到权重
  23. trainWeights = stocGradAscent1(array(trainData), trainLabels, 500)
  24. numTestVec = 0 # 记录测试样本的数量
  25. errorCount = 0 # 预测错误的数量
  26. for line in frTest.readlines():
  27. numTestVec += 1
  28. currLine = line.strip().split('\t')
  29. lineArr = []
  30. for i in range(21):
  31. lineArr.append(float(currLine[i]))
  32. # 把训练好的权重应用到测试集上
  33. if int(classifyVector(array(lineArr), trainWeights)) != int(currLine[21]):
  34. errorCount += 1
  35. errorRate = float(errorCount)/numTestVec
  36. print 'The error rate of this test is %f' %errorRate
  37. return errorRate
  38. def multiTest():
  39. numTests = 10; errorSum=0.0
  40. for k in range(numTests):
  41. errorSum += colicTest()
  42. print "after %d iterations the average error rate is: %f" % (numTests, errorSum/float(numTests))
测试效果如下:

每次的错误率不同是因为随机策略导致的。

小结


 LR优点:计算代价不高,易于理解和实现
LR缺点:容易欠拟合,分类精度可能不高
使用数据类型:数值型和标称型

梯度上升是非常常用的最优化方法
随机梯度上升算法降低了计算复杂度,而且这是一个在线学习算法

缺失数据处理是数据分析乃至机器学习的重要组成部分,它没有标准的做法,取决于具体情况的不同


【4】Logistic回归的更多相关文章

  1. 神经网络、logistic回归等分类算法简单实现

    最近在github上看到一个很有趣的项目,通过文本训练可以让计算机写出特定风格的文章,有人就专门写了一个小项目生成汪峰风格的歌词.看完后有一些自己的小想法,也想做一个玩儿一玩儿.用到的原理是深度学习里 ...

  2. 机器学习——Logistic回归

    1.基于Logistic回归和Sigmoid函数的分类 2.基于最优化方法的最佳回归系数确定 2.1 梯度上升法 参考:机器学习--梯度下降算法 2.2 训练算法:使用梯度上升找到最佳参数 Logis ...

  3. logistic回归

    logistic回归 回归就是对已知公式的未知参数进行估计.比如已知公式是$y = a*x + b$,未知参数是a和b,利用多真实的(x,y)训练数据对a和b的取值去自动估计.估计的方法是在给定训练样 ...

  4. Logistic回归 python实现

    Logistic回归 算法优缺点: 1.计算代价不高,易于理解和实现2.容易欠拟合,分类精度可能不高3.适用数据类型:数值型和标称型 算法思想: 其实就我的理解来说,logistic回归实际上就是加了 ...

  5. Logistic回归的使用

    Logistic回归的使用和缺失值的处理 从疝气病预测病马的死亡率 数据集: UCI上的数据,368个样本,28个特征 测试方法: 交叉测试 实现细节: 1.数据中因为存在缺失值所以要进行预处理,这点 ...

  6. 如何在R语言中使用Logistic回归模型

    在日常学习或工作中经常会使用线性回归模型对某一事物进行预测,例如预测房价.身高.GDP.学生成绩等,发现这些被预测的变量都属于连续型变量.然而有些情况下,被预测变量可能是二元变量,即成功或失败.流失或 ...

  7. SPSS数据分析—配对Logistic回归模型

    Lofistic回归模型也可以用于配对资料,但是其分析方法和操作方法均与之前介绍的不同,具体表现 在以下几个方面1.每个配对组共有同一个回归参数,也就是说协变量在不同配对组中的作用相同2.常数项随着配 ...

  8. SPSS数据分析—多分类Logistic回归模型

    前面我们说过二分类Logistic回归模型,但分类变量并不只是二分类一种,还有多分类,本次我们介绍当因变量为多分类时的Logistic回归模型. 多分类Logistic回归模型又分为有序多分类Logi ...

  9. SPSS数据分析—二分类Logistic回归模型

    对于分类变量,我们知道通常使用卡方检验,但卡方检验仅能分析因素的作用,无法继续分析其作用大小和方向,并且当因素水平过多时,单元格被划分的越来越细,频数有可能为0,导致结果不准确,最重要的是卡方检验不能 ...

  10. Logistic回归分类算法原理分析与代码实现

    前言 本文将介绍机器学习分类算法中的Logistic回归分类算法并给出伪代码,Python代码实现. (说明:从本文开始,将接触到最优化算法相关的学习.旨在将这些最优化的算法用于训练出一个非线性的函数 ...

随机推荐

  1. 夯实Java基础(十)——抽象类和接口

    转载自:http://cmsblogs.com/ 该博主的网站上干货非常!非常!非常多(说三遍),强烈推荐大家前去学习. 接口和内部类为我们提供了一种将接口与实现分离的更加结构化的方法 抽象类与接口是 ...

  2. 通俗地说决策树算法(三)sklearn决策树实战

    前情提要 通俗地说决策树算法(一)基础概念介绍 通俗地说决策树算法(二)实例解析 上面两篇介绍了那么多决策树的知识,现在也是时候来实践一下了.Python有一个著名的机器学习框架,叫sklearn.我 ...

  3. Docker最简单入门之(二)——简单使用Docker

    0.前言 本章主要写一些怎么使用Docker,拉取镜像和创建容器等之类的Docker的常用基本操作.在开始写之前,大家需要明白一下几个名词的含义 1.镜像:镜像是指一个类似于安装包的东西,尝试安装过电 ...

  4. 【Vue的路由,SPA概念】

    前言 本章是为了以后实现前端页面的搭建而写的, 重点在于如何实现 单页Web应用 因为相对于以前的传统多页面web,有很大的缺陷. 那么就必须了解一下Vue的路由设置. SPA的概念 总的而言,我们知 ...

  5. JavaScript 数组、字符串、Map、Set 方法整理

    在线阅读 https://www.kancloud.cn/chenmk/web-knowledges/1080519 数组 isArray():Array.isArray(value) 用于检测变量是 ...

  6. cs231n---语义分割 物体定位 物体检测 物体分割

    1 语义分割 语义分割是对图像中每个像素作分类,不区分物体,只关心像素.如下: (1)完全的卷积网络架构 处理语义分割问题可以使用下面的模型: 其中我们经过多个卷积层处理,最终输出体的维度是C*H*W ...

  7. AutoCAD C#二次开发

    https://www.cnblogs.com/gisoracle/archive/2012/02/19/2357925.html using System; using System.Collect ...

  8. Sublime Text 3 使用手册

    Ctrl+Shift+P:打开命令面板 Ctrl+P:搜索项目中的文件 Ctrl+G:跳转到第几行 Ctrl+W:关闭当前打开文件 Ctrl+Shift+W:关闭所有打开文件 Ctrl+Shift+V ...

  9. python + selenium webdriver 通过python来模拟鼠标、键盘操作,来解决SWFFileUpload调用系统底层弹出框无法定位问题

    Webdriver是基于浏览器操作的,当页面上传文件使用的是flash的控件SWFFileUpload调用的时候,调用的是系统底层的文件选择弹出框 这种情况,Webdriver暂时是不支持除页面外的其 ...

  10. 结合suctf-upload labs-RougeMysql再学习

    这篇主要记录一下这道题目的预期解法 做这道题首先要在自己的vps搭建一个rouge mysql,里面要填写需要读取客户端的文件名,即我们上传的phar文件路径 先搭一个rouge mysql测试看看: ...