Logistic回归算法_tensorflow 随机梯度上升-程序员宅基地

技术标签: 机器学习基础算法学习  

基于Logistic回归和Sigmoid函数的分类

对于二分类问题,需要找到这样一个函数,他对任意给定的输入输出0或1,海维赛德阶跃函数符合这一特性,但其在跳跃点处很难处理,因此我们用其他函数来代替,本章所用的函数为sigmoid函数该函数的表达式及图像如下所示

可以看到,当x趋于正无穷时,函数值趋近于1;当x趋于负无穷时,函数值趋近于0;

我们将输出大与0.5的归入1类,将输出小于0.5时归入0类。

假设输入数据的特征是(x0, x1, x2, …, xn),我们在每个特征上乘以一个回归系数 (w0, w1, w2, … , wn)

利用线性代数的知识,我们可以把式子简化为:

再将Z输入sigmoid函数就可以得到最终的值啦~

可以看到,式子中最重要的是要确定w(又称权重矩阵),那么应该怎么确定这个权重矩阵呢?

梯度上升法

梯度上升法的思想是:要找到某函数的最大值,最好的办法就是沿着该函数的梯度方向探寻。

梯度上升算法的公式如下,这里的f(w)为损失函数,关于损失函数的知识,可以参照吴恩达的机器学习视频或者网上的梯度上升算法的推导。损失函数代表了真实值与预测值之间的差异,我们对其求偏导即可得到权重矩阵的梯度,这里的alpha是学习率,学习率的选择是一项很大的学问,本章暂时给定学习率,只需知道选择合适的学习率是一个很重要的步骤,学习率太小会导致开销大,学习率太大会导致越来越偏离真实值。

以下是梯度上升法的具体例子

OK,有了理论支撑我们就可以开始写代码了

简单练习

作为练习,我们首先使用一个灰常简单的数据集

这是test.txt中的一小部分数据,可以看到数据有两个特征,最后有一个0,1的标签

先看一下我们需要导入的包,因为是从底层开始写,所以我们需要的特别简单(环境为python2.7)

from numpy import *		##实际不推荐这种写法
from math import exp

整个文档共有100个这样的数据,我们将其导入

def loaddataset():
    datamat = []; labelmat = []
    fr = open('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

定义sigmoid函数

def sigmoid0(inX):
    return 1.0/(1+exp(-inX))

然后写出梯度上升算法

"""未优化梯度上升算法"""
def gradascent(datamatin,classlabels):
    datamatrix = mat(datamatin)
    labelmat = mat(classlabels).transpose()
    m,n = shape(datamatrix)
    alpha = 0.001
    maxcycles = 500
    weights = ones((n,1))
    for k in range(maxcycles):
        h = sigmoid(datamatrix*weights)
        error = (labelmat - h)
        weights = weights + alpha*datamatrix.transpose()*error
    plotbestfit(weights)
    return weights

在运行之前,我们先对sigmoid函数做一个改写。可以看到传入sigmoid函数的参数dataamatrixweights是一个m1的矩阵,但是Python3.5并不支持用exp ()函数直接对矩阵进行操作。这一点书中并没有指出,算是一个勘误。以下给出风车自己的方法,这个方法有一点蠢,既然不支持直接对矩阵中的每个元素进行操作,那我们就先把它转换为numpy中的数组,然后用数组遍历的方法来进行每个元素的sigmoid操作,最后别忘记再把它转成矩阵。修改后的sigmoid()函数如下所示

"""求sigmoid"""
def sigmoid(data):
    s = data.getA()
    datatemp = [[ 1.0/(1+exp(-s[i][j])) for j in range(len(s[i]))]for i in range(len(s))]
    datafinal = mat(datatemp)
    return datafinal

好了,这就可以开始测试了

"""测试代码"""
dataarr,labelmat = loaddataset
print(gradascent(dataarr,labelmat))

输出如下:

可以看到,我们的方法确实是有效的,但是写了这么久看到一行黑白的输出,是不是有些小失落,别急,我们来让这些数据可视化

绘制图形

这里直接给出代码,用到的只是一些基础的功能,搜索一下相关函数的功能很容易理解。风车也还在学进一步的图形绘制功能,一起加油~

"""画出决策边界"""
def plotbestfit(wei):
    import matplotlib.pyplot as plt
    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()
    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()

我们在程序末尾加上

plotbestfit(gradascent(dataarr,labelmat))

运行得到如下图像

可以看到结果对数据的划分还是很令人满意的

随机梯度上升算法

梯度上升法给出的结果很棒,但其本身仍有有一定的不足。梯度上升算法在每次更新权重矩阵时都要便利整个数据集,我们给出的test.txt只有100个样例,但若是有数十亿个样本,那么这样的方式复杂度就太高了。因此我们有了随机梯度算法。随机梯度算法,顾名思义,每次随机的取一个值(为了方便,下面的样例按顺序取一个值)来对我们的权重矩阵进行更新。

随机梯度上升算法的代码如下

"""随机梯度上升算法"""
def stogradascent(datamatrix,classlabels,num=150):
    m,n = shape(datamatrix)
    weights = ones(n)
    for j in range(num):
        dataindex = list(range(m))
        for i in range(m):
            alpha = 4/(1.0+j+i)+0.0001
            randindex = int(random.uniform(0,len(dataindex)))
            """此处代码为自己修改"""
            h = sigmoid0(sum(datamatrix[randindex]*weights))
            """sigmoid0()出现OverflowError:math range error"""
            error = classlabels[randindex] - h
            weights = weights + alpha * error * datamatrix[randindex]
            del(dataindex[randindex])
    return weights

这里的sigmoid0函数就是开头给出的

def sigmoid0(inX):
    return 1.0/(1+exp(-inX))

这一次我们传入的值sum(datamatrix[randindex]weights)并不是一个矩阵,sum()函数内两个矩阵的大小分别为1n和n1,因此得到的是一个11的矩阵,我们用这个值来更新我们的权重矩阵weights。

最后输入测试代码

dataarr,labelmat = loaddataset()
weights = stogradascent(array(dataarr),labelmat)
plotbestfit(weights)

可以看到如下结果

可以看到结果并没有梯度上升算法好,但这样的比较是不公平的,因为后者是在整个数据集上迭代了500次得到的,当然提升随机梯度算法的迭代次数num也能的到更好的结果。

小测试也做完了,这回来个实际应用吧!

从疝气病症预测病马的死亡率

给出的horseColicTraining.txt中每个样本有20个特征,并有一个标签,0代表未能存活,1代表可以存活。horseColicTest.txt作为测试集来判断我们训练出的模型的好坏。

话不多说,直接上代码

def classifyvector(inX,weights):
    prob = sigmoid0(sum(inX*weights))
    if prob > 0.5:return 1.0
    else:return 0.0

def colicTest():
    frTrain = open('horseColicTraining.txt')
    frTest = open('horseColicTest.txt')
    trainingSet = [];trainingLabels = []
    for line in frTrain.readlines():
        currLine = line.strip().split('\t')
        lineArr = []
        for i in range(21):
            lineArr.append(float(currLine[i]))
        trainingSet.append(lineArr)
        trainingLabels.append(float(currLine[21]))
    trainWeights = stogradascent(array(trainingSet),trainingLabels,1000)
    errorCount = 0; numTestVec = 0.0
    for line in frTest.readlines():
        numTestVec += 1.0
        currLine = line.strip().split('\t')
        lineArr=[]
        for i in range(21):
            lineArr.append(float(currLine[i]))
        if int(classifyvector(array(lineArr),trainWeights)) != int(currLine[21]):
            errorCount += 1
    errorRate = (float(errorCount)/numTestVec)
    print("the error rata of this test is:%f" %errorRate)
    return errorRate
def multiTest():
    numTests = 10; errorSum=0.0
    for k in range(numTests):
        errorSum += colicTest()
    print("after %d iterations the average error rata is:%f" %(numTests,errorSum/float(numTests)))

"""测试代码"""
multiTest()

运行结果如下:

tensorflow实现

数据集

本次我们所使用的数据集,是MNIST数据集。MNIST是一个手写数字数据库,它有60000个训练样本集和10000个测试样本集。它是NIST数据库的一个子集。其中每张图片固定大小为28281,最后的数字1表示一个通道,即灰度图。

我们首先导入一些必要的模块

import tensorflow as tf
import matplotlib.pyplot as plt
import input_data
mnist=input_data.read_data_sets("MNIST_data/",one_hot=True)

这里input_data.read_data_sets函数生成的类会自动将MNIST数据集划分为train,validation和test三个数据集,其中train中有55000张图片,validation集合内有5000张图片,这两个集合合起来就是MNIST的训练数据集。剩下的test集合中有10000张图片,这是MNIST的测试数据集。我们的每张图片将被处理成一个长度784(28281)一维数组。

解释一下one_hot,我们最后的分类有10个数字,我们采用二分类的模型,one_hot=True就是让其中的一个元素为1,其余元素为0,这样就将10分类简化为2分类啦~

我们可以打印MNIST数据集中的一张图片来看看效果

img = mnist.test.images[0]
image = img.reshape(28,28)
plt.imshow(image)
plt.show()

这里我们打印test数据集中的第一张图片,打印之前我们先通过reshape将其还原为一个28*28的像素矩阵,然后用matplotlib把他打印出来

大概就是这个样子,但是其实际为一个灰度图,只有黑白两种颜色

实现SLogistic Regression

"""定义出一些参数"""
training_num = 20 #总共训练几轮
learning_rate = 0.01 #学习率
batch_size = 100 #每次取一部分图片,随机梯度上升

"""mnist Graph input"""
x  = tf.placeholder("float",shape=[None,784])
y_ = tf.placeholder("float",shape=[None,10])

"""定义权重矩阵W和偏置b"""
W = tf.Variable(tf.zeros([784,10]))
b = tf.Variable(tf.zeros([10]))

"""softmax计算输出"""
y = tf.nn.softmax(tf.matmul(x,W) + b)

"""用交叉熵作为损失函数"""
cost = tf.reduce_mean(-tf.reduce_sum(y_*tf.log(y),reduction_indices=1))

"""梯度下降优化器"""
train_step = tf.train.GradientDescentOptimizer(learning_rate).minimize(cost)

我们定义了一些参数,这些参数在后面的过程中会用到,写在前面是为了在环境改变时能快速的做相应的调整。这里的reduce_sum根据函数名很容易知道是求和,而外面的的reduce_mean自然是求平均数,这里解释一下reduction_indices。这个参数表示函数处理的维度,若没有写则默认为None,即把输入的tensor降到0维,也就是一个数。

placeholder是一个占位符,在后面计算时需要给他相应的值。

创建Session

注意一定要有Session!!!不然上面所有的工作都只是创建了一个graph,实际并不做任何计算。我们需要用Session来计算图或图的一部分。

在开始之前还要对所有的变量进行初始化。

这里的batch_size每次取训练集中的一小部分,这样可以一定程度上增大最后到达全局最优的可能性,也相当于一个随机的梯度下降。我们用feed_dict将数据“喂给”前文所提到的占位符。

"""初始化所有变量"""
init = tf.initialize_all_variables()
with tf.Session() as sess:
    sess.run(init)
    #训练20轮
    for lun in range(training_num):
        avg_cost = 0;
        num = int(mnist.train.num_examples/batch_size)
        for i in range(num):
            batch = mnist.train.next_batch(batch_size)
            c=sess.run([train_step,cost],feed_dict={
    x:batch[0],y_:batch[1]})
            avg_cost += c[1]/num
        print("after %d training,the cost is %.9f" %(lun+1,avg_cost))

    print("training over!")
    """测试其准确率"""
    correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
    accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
    print("Accuracy:",sess.run(accuracy, feed_dict={
    x: mnist.test.images, y_: mnist.test.labels}))

准确率

可以看到我们最后的准确率是91%左右,这个结果怎么样呢?很抱歉,91的准确率并不是很理想,不过也别灰心,这是我们的第一个算法,也是灰常灰常简单的一种,后面还有很多美妙神奇的算法等着我们去学习,加油吧,骚年!

风车是个渣渣,如果文章有什么错误,欢迎指出~

参考文献

周志华《机器学习》

李锐《机器学习实战》

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_41152041/article/details/84757289

智能推荐

使用nginx解决浏览器跨域问题_nginx不停的xhr-程序员宅基地

文章浏览阅读1k次。通过使用ajax方法跨域请求是浏览器所不允许的,浏览器出于安全考虑是禁止的。警告信息如下:不过jQuery对跨域问题也有解决方案,使用jsonp的方式解决,方法如下:$.ajax({ async:false, url: 'http://www.mysite.com/demo.do', // 跨域URL ty..._nginx不停的xhr

在 Oracle 中配置 extproc 以访问 ST_Geometry-程序员宅基地

文章浏览阅读2k次。关于在 Oracle 中配置 extproc 以访问 ST_Geometry,也就是我们所说的 使用空间SQL 的方法,官方文档链接如下。http://desktop.arcgis.com/zh-cn/arcmap/latest/manage-data/gdbs-in-oracle/configure-oracle-extproc.htm其实简单总结一下,主要就分为以下几个步骤。..._extproc

Linux C++ gbk转为utf-8_linux c++ gbk->utf8-程序员宅基地

文章浏览阅读1.5w次。linux下没有上面的两个函数,需要使用函数 mbstowcs和wcstombsmbstowcs将多字节编码转换为宽字节编码wcstombs将宽字节编码转换为多字节编码这两个函数,转换过程中受到系统编码类型的影响,需要通过设置来设定转换前和转换后的编码类型。通过函数setlocale进行系统编码的设置。linux下输入命名locale -a查看系统支持的编码_linux c++ gbk->utf8

IMP-00009: 导出文件异常结束-程序员宅基地

文章浏览阅读750次。今天准备从生产库向测试库进行数据导入,结果在imp导入的时候遇到“ IMP-00009:导出文件异常结束” 错误,google一下,发现可能有如下原因导致imp的数据太大,没有写buffer和commit两个数据库字符集不同从低版本exp的dmp文件,向高版本imp导出的dmp文件出错传输dmp文件时,文件损坏解决办法:imp时指定..._imp-00009导出文件异常结束

python程序员需要深入掌握的技能_Python用数据说明程序员需要掌握的技能-程序员宅基地

文章浏览阅读143次。当下是一个大数据的时代,各个行业都离不开数据的支持。因此,网络爬虫就应运而生。网络爬虫当下最为火热的是Python,Python开发爬虫相对简单,而且功能库相当完善,力压众多开发语言。本次教程我们爬取前程无忧的招聘信息来分析Python程序员需要掌握那些编程技术。首先在谷歌浏览器打开前程无忧的首页,按F12打开浏览器的开发者工具。浏览器开发者工具是用于捕捉网站的请求信息,通过分析请求信息可以了解请..._初级python程序员能力要求

Spring @Service生成bean名称的规则(当类的名字是以两个或以上的大写字母开头的话,bean的名字会与类名保持一致)_@service beanname-程序员宅基地

文章浏览阅读7.6k次,点赞2次,收藏6次。@Service标注的bean,类名:ABDemoService查看源码后发现,原来是经过一个特殊处理:当类的名字是以两个或以上的大写字母开头的话,bean的名字会与类名保持一致public class AnnotationBeanNameGenerator implements BeanNameGenerator { private static final String C..._@service beanname

随便推点

二叉树的各种创建方法_二叉树的建立-程序员宅基地

文章浏览阅读6.9w次,点赞73次,收藏463次。1.前序创建#include<stdio.h>#include<string.h>#include<stdlib.h>#include<malloc.h>#include<iostream>#include<stack>#include<queue>using namespace std;typed_二叉树的建立

解决asp.net导出excel时中文文件名乱码_asp.net utf8 导出中文字符乱码-程序员宅基地

文章浏览阅读7.1k次。在Asp.net上使用Excel导出功能,如果文件名出现中文,便会以乱码视之。 解决方法: fileName = HttpUtility.UrlEncode(fileName, System.Text.Encoding.UTF8);_asp.net utf8 导出中文字符乱码

笔记-编译原理-实验一-词法分析器设计_对pl/0作以下修改扩充。增加单词-程序员宅基地

文章浏览阅读2.1k次,点赞4次,收藏23次。第一次实验 词法分析实验报告设计思想词法分析的主要任务是根据文法的词汇表以及对应约定的编码进行一定的识别,找出文件中所有的合法的单词,并给出一定的信息作为最后的结果,用于后续语法分析程序的使用;本实验针对 PL/0 语言 的文法、词汇表编写一个词法分析程序,对于每个单词根据词汇表输出: (单词种类, 单词的值) 二元对。词汇表:种别编码单词符号助记符0beginb..._对pl/0作以下修改扩充。增加单词

android adb shell 权限,android adb shell权限被拒绝-程序员宅基地

文章浏览阅读773次。我在使用adb.exe时遇到了麻烦.我想使用与bash相同的adb.exe shell提示符,所以我决定更改默认的bash二进制文件(当然二进制文件是交叉编译的,一切都很完美)更改bash二进制文件遵循以下顺序> adb remount> adb push bash / system / bin /> adb shell> cd / system / bin> chm..._adb shell mv 权限

投影仪-相机标定_相机-投影仪标定-程序员宅基地

文章浏览阅读6.8k次,点赞12次,收藏125次。1. 单目相机标定引言相机标定已经研究多年,标定的算法可以分为基于摄影测量的标定和自标定。其中,应用最为广泛的还是张正友标定法。这是一种简单灵活、高鲁棒性、低成本的相机标定算法。仅需要一台相机和一块平面标定板构建相机标定系统,在标定过程中,相机拍摄多个角度下(至少两个角度,推荐10~20个角度)的标定板图像(相机和标定板都可以移动),即可对相机的内外参数进行标定。下面介绍张氏标定法(以下也这么称呼)的原理。原理相机模型和单应矩阵相机标定,就是对相机的内外参数进行计算的过程,从而得到物体到图像的投影_相机-投影仪标定

Wayland架构、渲染、硬件支持-程序员宅基地

文章浏览阅读2.2k次。文章目录Wayland 架构Wayland 渲染Wayland的 硬件支持简 述: 翻译一篇关于和 wayland 有关的技术文章, 其英文标题为Wayland Architecture .Wayland 架构若是想要更好的理解 Wayland 架构及其与 X (X11 or X Window System) 结构;一种很好的方法是将事件从输入设备就开始跟踪, 查看期间所有的屏幕上出现的变化。这就是我们现在对 X 的理解。 内核是从一个输入设备中获取一个事件,并通过 evdev 输入_wayland

推荐文章

热门文章

相关标签