前言

本文将介绍机器学习分类算法中的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 20**-**-** @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. 第十三篇:K-Means 聚类算法原理分析与代码实现

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

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

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

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

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

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

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

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

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

  8. Lineage逻辑回归分类算法

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

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

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

随机推荐

  1. vim显示行号、语法高亮、自动缩进、添加下划线的设置

    ubuntu默认是没有安装vim的,所以设置以前请先安装vim:sudo apt-get install vim. 然后 打开vim的配置文件:sudo vim /etc/vim/vimrc 或者 s ...

  2. DRAM 各项基本参数记录

    记录一下DRAM的各项基本参数 tCL CAS Latency CAS 潜伏期, 列地址寻找/读写命令执行完毕,准备要读出来,需要一个延时缓一缓 tRAS: RAS Active Timeing 行有 ...

  3. JavaScript 深入理解作用域链

    第一步. 定义后:每个已定义函数,都有一个内在属性[scope],其对应一个对象的列表,列表中的对象仅能内部访问. 例如:建立一个全局函数A,那么A的[Scope]内部属性中只包含一个全局对象(Glo ...

  4. 老生常谈:vim 配置

    1.自动补全 插件名字:NeoComplCache 下载地址:http://www.vim.org/scripts/script.php?script_id=2620 配置:把文件直接复制到vimfi ...

  5. parted创建LVM

    parted创建LVM 把一块1T硬盘全部设为LVM #parted /dev/sdb >mklabel gpt 由于MBR分区表只支持2T硬盘,所以如果大于2T必须用GPT分区表 >pr ...

  6. axis client error Bad envelope tag: definitions

    http://blog.csdn.net/lifuxiangcaohui/article/details/8090503 ——————————————————————————————————————— ...

  7. jquery-easyui 中表格的行编辑功能

    具体实现代码如下: <table id="tt"></table> $('#tt').datagrid({ title:'Editable DataGrid ...

  8. 在使用R做数据挖掘时,最常用的数据结构莫过于dataframe了,下面列出几种常见的dataframe的操作方法

    原网址 http://blog.sina.com.cn/s/blog_6bb07f83010152z0.html 在使用R做数据挖掘时,最常用的数据结构莫过于dataframe了,下面列出几种常见的d ...

  9. 关于Cocos2d-x中父子节点的互动

    1.子节点可以通过this->getParent()来获得相应的父节点,并且进行强制类型转换. ((Scene*)this->getParent())->getPhysicsWorl ...

  10. selenium测试(Java)--上传文件(十五)

    1. 当页面中是通过input标签实现上传功能时,可以使用selenium来上传功能. 如下: package com.test.upload; import java.io.File; import ...