前言

  本文将介绍机器学习分类算法中的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. Epson机械手4轴6轴示意图

    世界坐标系(World Coordinate System,简称WCS)是由三个垂直并相交的坐标轴X轴.Y轴和Z轴构成,一般显示在绘图区域的左下角,如图1-7所示.X轴和Y轴的交点就是坐标原点O,X轴 ...

  2. C++变量初始化问题

    初始化和赋值的区别 在C++中,变量初始化和赋值操作符是两个完全不同的概念. 初始化不是赋值,初始化的含义是创建变量分配存储空间时为其赋一个初始值,而赋值的含义是把内存空间的当前值擦除,用一个新值代替 ...

  3. Sublime Text 3 中文乱码的解决方法

    Sublime Text 3 中文乱码表现如下图: 解决方法很简单,三步搞定: 步骤一: 下载ConvertToUTF8,下载地址:http://pan.baidu.com/s/1gd5SWmB 步骤 ...

  4. 转载css的background-position

    这是一个有趣的话题 其实我并不确切的平时大家是怎么去应用或者玩转一个属性,一个值.我能肯定的是这些东西都有不少的可玩性. 我今天要聊的 background-position 应该已经被大家玩得色彩斑 ...

  5. stella mccartney falabella foldover tote a few eye observed

    Lately, the particular Heyuan City Courtroom retrial, in order to commit the criminal offense of cou ...

  6. Service Broker应用(2):不同server间的数据传输,包含集群

    不同Server之间的数据传输,包含DB使用AlwaysOn 配置脚本: SQL Server Service Broker 跨集群通信 具体的TSQL 脚本语句如下.注意的是TSQL语句是在发送方还 ...

  7. windows下安装rabbitmq的php扩展amqp

    最近研究rabbitmq队列,linux安装这样的软件一向都是很方便的,但是windows可能会比较麻烦,所以对windows的安装做个记录. windows上使用的php扩展为dll文件,首先去下载 ...

  8. Mysqli封装

    <?php //headerheader('content-type:text/html;charset=UTF-8'); class DB {    //定义属性    private $ho ...

  9. .NET微信模拟登录及{base_resp:{ret:-4,err_msg:nvalid referrer}}的解决办法

    12年的时候写了些关于微信开发的内容,当时看好这个东西,可惜当时腾讯开放的权限太少,之后的一年多时间没有太关注了. 现在又要重新开始微信开发的阵容了,微信只是个入口,微网站才是趋势. 我是个水货,所以 ...

  10. (spring-第20回【AOP基础篇】)Spring与事务

    要想了解Spring的事务,首先要了解数据库事务的基本知识,数据库并发会产生很多问题,Spring使用ThreadLocal技术来处理这些问题,那么我们必须了解Java的ThreadLocal技术.下 ...