前言

  本文将介绍机器学习分类算法中的Logistic回归分类算法并给出伪代码,Python代码实现。

  (说明:从本文开始,将接触到最优化算法相关的学习。旨在将这些最优化的算法用于训练出一个非线性的函数,以用于分类。)

算法原理  

  首先要提到的概念是回归。

  对于回归这个概念,在以后的文章会有系统而深入的学习。简单的说,回归就是用一条线对N多数据点进行一个拟合,这个拟合的过程就叫做回归。

  Logistic回归分类算法就是对数据集建立回归公式,以此进行分类。

  而至于如何寻找最佳回归系数,或者说是分类器的训练,就需要使用到最优化算法了。

回归分类器的形式

  基本形式是用每个特征都乘以一个回归系数,然后把所有的结果值相加。

  这样算出的很多结果都是连续的,不利于分类,故可以将结果再带入到一个Sigmoid函数以得到一些比较离散的分类结果。

  Sigmoid函数的轮廓如下:

  

  这样,计算的结果会是一个0-1的值。进而0.5以上归为一类,以下归为一类即可。(一般的逻辑回归只能解决两个分类的问题)

  接下来的工作重点就转移到了最佳回归系数的确定了。

最佳回归系数的确定

  确定最佳回归系数的过程,也就是对数据集进行训练的过程。

  求最佳回归系数的步骤如下:

    1. 列出分类函数:

    (θ 指回归系数,在实践中往往会再对结果进行一个Sigmoid转换)

    2. 给出分类函数对应的错误估计函数:

    

    (m为样本个数)

    只有当某个θ向量使上面的错误估计函数J(θ)取得最小值的时候,这个θ向量才是最佳回归系数向量。

    3. 采用梯度下降法或者最小二乘法求错误函数取得最小值的时候θ的取值:

    

    为表述方便,上式仅为一个样本的情况,实际中要综合多个样本的情况需要进行一个求和 (除非你使用后面会介绍的随机梯度上升算法),具体请参考下面的代码实现部分。

  将步骤 2 中的错误函数加上负号,就可以把问题转换为求极大值,梯度下降法转换为梯度上升法。

  更详尽的推导部分,在以后专门分析回归的文章中给出。

基于梯度上升法的最佳回归参数拟合

  梯度上升法求最大值的核心思想是将自变量沿着目标函数的梯度方向移动,一直移动到指定的次数或者说某个允许的误差范围。

  基于梯度上升法的分类伪代码:

 每个回归系数初始化为1
重复R次:
计算整个数据集的梯度
使用 alpha * gradient 更新回归系数向量
返回回归系数

    下面给出完整的实现及测试代码(用到的数据集文件共 4 列,前 3 列为特征,最后一列为分类结果):

 #!/usr/bin/env python
# -*- coding:UTF-8 -*- '''
Created on 2014-12-29 @author: fangmeng
''' import numpy #=====================================
# 输入:
# 空
# 输出:
# dataMat: 测试数据集
# labelMat: 测试分类标签集
#=====================================
def loadDataSet():
'创建测试数据集,分类标签集并返回。' # 测试数据集
dataMat = [];
# 测试分类标签集
labelMat = []
# 文本数据源
fr = open('/home/fangmeng/testSet.txt') # 载入数据
for line in fr.readlines():
lineArr = line.strip().split()
dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])])
labelMat.append(int(lineArr[2])) return dataMat,labelMat #=====================================
# 输入:
# inX: 目标转换向量
# 输出:
# 1.0/(1+numpy.exp(-inX)): 转换结果
#=====================================
def sigmoid(inX):
'sigmoid转换函数' return 1.0/(1+numpy.exp(-inX)) #=====================================
# 输入:
# dataMatIn: 数据集
# classLabels: 分类标签集
# 输出:
# weights: 最佳拟合参数向量
#=====================================
def gradAscent(dataMatIn, classLabels):
'基于梯度上升法的logistic回归分类器' # 将数据集,分类标签集存入矩阵类型。
dataMatrix = numpy.mat(dataMatIn)
labelMat = numpy.mat(classLabels).transpose() # 上升步长度
alpha = 0.001
# 迭代次数
maxCycles = 500
# 初始化回归参数向量
m,n = numpy.shape(dataMatrix)
weights = numpy.ones((n,1)) # 对回归系数进行maxCycles次梯度上升
for k in range(maxCycles):
h = sigmoid(dataMatrix*weights)
error = (labelMat - h)
weights = weights + alpha * dataMatrix.transpose()* error return weights def test():
'测试' dataArr, labelMat = loadDataSet()
print gradAscent(dataArr, labelMat) if __name__ == '__main__':
test()

  测试结果:

  

拟合结果展示

  可使用matplotlib画决策边界,用作分析拟合结果是否达到预期。

  绘制及测试部分代码如下所示:

 #======================================
# 输入:
# weights: 回归系数向量
# 输出:
# 图形化的决策边界演示
#======================================
def plotBestFit(weights):
'决策边界演示' import matplotlib.pyplot as plt
# 获取数据集 分类标签集
dataMat,labelMat=loadDataSet()
dataArr = numpy.array(dataMat) # 两种分类下的两种特征列表
xcord1 = []; ycord1 = []
xcord2 = []; ycord2 = []
for i in range(numpy.shape(dataArr)[0]):
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 = numpy.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() def test():
'测试' dataArr, labelMat = loadDataSet()
weights = gradAscent(dataArr, labelMat)
plotBestFit(weights.getA())

  测试结果:

  

更好的求最值方法 - 随机梯度上升

  Logistic回归的本质其实就是求拟合参数,而求拟合参数最核心的就是求错误估计函数的最小值。

  仔细分析上面的代码,会发现该分类的效率做多的耗费也是在求最值上面。由于每次都要用所有数据来计算梯度,导致数据集非常大的时候,该算法很不给力。

  实践表明,每次仅仅用一个样本点来更新回归系数,当所有样本算完,也能达到相似的效果(仅仅是相似,或者说接近)。

  由于可以在每个样本到达的时候对分类器进行增量式更新,因此随机梯度上升算法其实是一个在线学习算法。

  基于随机梯度上升的分类伪代码:

 所有回归系数初始化为1
对数据集中的每个样本:
计算该样本的梯度
使用 alpha * gradient 更新回归系数值
返回回归系数值

  请对比上面的基本梯度上升算法进行理解学习。

  优化之后的分类算法函数如下:

 #=====================================
# 输入:
# dataMatIn: 数据集(注意是向量类型)
# classLabels: 分类标签集
# 输出:
# weights: 最佳拟合参数向量
#=====================================
def stocGradAscent0(dataMatrix, classLabels):
'基于随机梯度上升法的logistic回归分类器' m,n = numpy.shape(dataMatrix)
# 上升步长度
alpha = 0.01
# 初始化回归参数向量
weights = numpy.ones(n) # 对回归系数进行样本数量次数的梯度上升,每次上升仅用一个样本。
for i in range(m):
h = sigmoid(sum(dataMatrix[i]*weights))
error = classLabels[i] - h
weights = weights + alpha * error * dataMatrix[i]
return weights

  你也许会疑惑 "不是说随机梯度上升算法吗?随机呢?",不用急,很快就会提到这个。

  分析优化后的代码可以看到两个区别:一个是当前分类结果变量h和误差变量都是数值类型(之前为向量类型),二是无矩阵转换过程,数据集为numpy向量的数组类型。

  测试结果:

  

  对比优化前的算法结果,可以看出分类错误率更高了。

  优化后的效果反而更差了?这样说有点不公平,因为优化后的算法只是迭代了100次,而优化前的足足有500次。

  那么接下来可以进一步优化,理论依据为:增加迭代计算的次数,当达到一个接近收敛或者已经收敛的状态时,停止迭代。

  那么如何做到这点呢?

  第一是要动态的选定步长,第二,就是每次随机的选定样本,这就是为什么叫做随机梯度上升算法了。

  最终修改后的分类器如下:

 #=====================================
# 输入:
# dataMatIn: 数据集(注意是向量类型)
# classLabels: 分类标签集
# 输出:
# weights: 最佳拟合参数向量
#=====================================
def stocGradAscent1(dataMatrix, classLabels, numIter=150):
'基于随机梯度上升法的logistic回归分类器' m,n = numpy.shape(dataMatrix)
weights = numpy.ones(n) # 迭代次数控制
for j in range(numIter):
# 样本选择集
dataIndex = range(m)
# 随机选取样本遍历一轮
for i in range(m):
# 动态修正步长
alpha = 4/(1.0+j+i)+0.0001
# 随机选取变量进行梯度上升
randIndex = int(numpy.random.uniform(0,len(dataIndex)))
h = sigmoid(sum(dataMatrix[randIndex]*weights))
error = classLabels[randIndex] - h
weights = weights + alpha * error * dataMatrix[randIndex]
# 从选择集中删除已经使用过的样本
del(dataIndex[randIndex])
return weights

  运行结果:

  

  这次,和最原始的基于梯度上升法分类器的结果就差不多了。但是迭代次数大大的减少了。

  网上也有一些非常严格的证明随机梯度上升算法的收敛速度更快(相比基础梯度上升算法)的证明,有兴趣的读者可以查找相关论文。

小结

  1. 逻辑回归的计算代价不高,是很常用的分类算法。集中基于随机梯度上升的逻辑回归分类器能够支持在线学习。

  2. 但逻辑回归算法缺点很明显 - 一般只能解决两个类的分类问题。

  3. 另外逻辑回归容易欠拟合,导致分类的精度不高。

  

Logistic回归分类算法原理分析与代码实现的更多相关文章

  1. 第七篇:Logistic回归分类算法原理分析与代码实现

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

  2. 第一篇:K-近邻分类算法原理分析与代码实现

    前言 本文介绍机器学习分类算法中的K-近邻算法并给出伪代码与Python代码实现. 算法原理 首先获取训练集中与目标对象距离最近的k个对象,然后再获取这k个对象的分类标签,求出其中出现频数最大的标签. ...

  3. logistic回归介绍以及原理分析

    1.什么是logistic回归? logistic回归虽然说是回归,但确是为了解决分类问题,是二分类任务的首选方法,简单来说,输出结果不是0就是1 举个简单的例子: 癌症检测:这种算法输入病理图片并且 ...

  4. Apriori 关联分析算法原理分析与代码实现

    前言 想必大家都听过数据挖掘领域那个经典的故事 - "啤酒与尿布" 的故事. 那么,具体是怎么从海量销售信息中挖掘出啤酒和尿布之间的关系呢? 这就是关联分析所要完成的任务了. 本文 ...

  5. 第十四篇:Apriori 关联分析算法原理分析与代码实现

    前言 想必大家都听过数据挖掘领域那个经典的故事 - "啤酒与尿布" 的故事. 那么,具体是怎么从海量销售信息中挖掘出啤酒和尿布之间的关系呢? 这就是关联分析所要完成的任务了. 本文 ...

  6. K-Means 聚类算法原理分析与代码实现

    前言 在前面的文章中,涉及到的机器学习算法均为监督学习算法. 所谓监督学习,就是有训练过程的学习.再确切点,就是有 "分类标签集" 的学习. 现在开始,将进入到非监督学习领域.从经 ...

  7. 第十三篇:K-Means 聚类算法原理分析与代码实现

    前言 在前面的文章中,涉及到的机器学习算法均为监督学习算法. 所谓监督学习,就是有训练过程的学习.再确切点,就是有 "分类标签集" 的学习. 现在开始,将进入到非监督学习领域.从经 ...

  8. Lineage逻辑回归分类算法

    Lineage逻辑回归分类算法 线性回归和逻辑回归参考文章: http://blog.csdn.net/viewcode/article/details/8794401 http://www.cnbl ...

  9. Logistic Algorithm分类算法的Octave仿真

    本次Octave仿真解决的问题是,根据两门入学考试的成绩来决定学生是否被录取,我们学习的训练集是包含100名学生成绩及其录取结果的数据,需要设计算法来学习该数据集,并且对新给出的学生成绩进行录取结果预 ...

随机推荐

  1. #define DELAY_ONE_MICROSECOND (-10) 时间是负数的原因

    以下摘自DOOM的博文<内核同步对象> http://blog.csdn.net/lqk1985/article/details/2541867 “最后一个参数&timeout是一 ...

  2. Oracle 添加第二个实例 和 监听

    1.添加第二个实例 配置和移植工具 -->Database Configuration Assistant 然后一步一步创建实例(实例名为ORCL2) 创建成功后会在系统的服务里面有个服务名称为 ...

  3. 简易线程池Thread Pool

    1. 基本思路 写了个简易的线程池,基本的思路是: 有1个调度线程,负责维护WorkItem队列.管理线程(是否要增加工作线程).调度(把工作项赋给工作线程)等 线程数量随WorkItem的量动态调整 ...

  4. windows10 声音图标总是被禁用,检测显示:扬声器,耳机或者耳机已拔出

    参考来源:http://jingyan.baidu.com/article/90bc8fc85de19df652640c7f.html 控制面板/应用和声音/Realtek高清晰音频管理器 点击右上角 ...

  5. Maven 排除第三方jar包所依赖的其他依赖

    单依赖过滤:可以过滤一个或者多个,如果过滤多个要写多个<exclusion>. <dependency> <groupId>org.apache.hbase< ...

  6. android学习之RadioButton和CheckBox

    移通152 余继彪 RadioBuuton是一个单选按钮,CheckBox是一个复选按钮 . RadioButton的使用 ,首先要将RadioButton放在RadioGroup中,RadioGro ...

  7. php 循环删除目录中的过期文件

            $savepath1 = 'Public/biaoqian/upload';         $path1 = dir($savepath1);           while (($ ...

  8. 解决小米wifi在windows10无法创建问题

    1.打开小米随身WIFI客户端安装文件夹(软件安装在那个盘,就在那个盘里找). 2.D:\Program Files (x86)\XiaoMi\MiWiFi\drivers\Win81x64(系统是3 ...

  9. AngularJS时间轴指令

    是基于ion.rangeSlider.js,主要代码如下: <link rel="stylesheet" type="text/css" href=&qu ...

  10. JavaScript document属性和方法

    JavaScript document属性和方法 --------------------------------------------属性: 1. Attributes     存储节点的属性列表 ...