《Machine Learning in action》- (笔记)之Logistic regression(1_基础篇)

本文是《Machine Learning in action》中逻辑回归的学习笔记。介绍了逻辑回归与梯度上升算法,逻辑回归用于二分类问题,利用Sigmoid函数和交叉熵代价函数。通过Python 3.7进行实战,包括数据准备、训练算法和绘制决策边界,最后总结了逻辑回归的一般步骤。

《Machine Learning in action》,机器学习实战(笔记)之Logistic regression

使用工具

- Python3.7
- pycharm
- anaconda
- jupyter notebook

一、 前言

  • 在这里我们将更多的用书中的内容,更多的公式到额推导就不在这里介绍了,但是还是会适当的介绍一些了,因为本身也是刚开始学习的,所以自己对公式的把握也不是那么好,所以这里就不一一详细的介绍了

二、Logistic regression与 The gradient ascent algorithm(梯度上升算法)

  • 针对于回归的问题,有线性回归和逻辑回归,但是两者却是有很大的区别,Logistic 回归主要就是做的分类的问题,二线性回归就是针对回归的问题
  • Logistic回归是众多分类算法中的一员。通常,Logistic回归用于二分类问题,例如预测明天是否会下雨。当然它也可以用于多分类问题,正对与多分类的问题,也就是将多分类的问题装换为多个二分类进行处理,这样还是会回归到二分类的问题,所以在这里我们主要讲的就是二分类的问题。

1. Logistic regression

  • 针对于Logistic 回归,我们可以用下面的例子来解释
    在这施工方里插入图片描述

  • 如图我们的获得了上面的一些数据,现在用通过一条直线对这些数据进行拟合,从而我们将这个过程称为:回归,这一条直线就是我们的最佳拟合直线,如下图所示:
    在这里插入图片描述

  • Logistic 回归是一种二分类的算法,它利用了Sigmoid函数,将阈值都锁定在0到1之间,Logistic本质上是一个基于条件概率的判别模型(Discriminative Model)。

  • 现在我们来了解一些我们的Sigmoid函数,
    -在这里插入图片描述
    可以观察它的图形
    在这里插入图片描述

  • 当然在这里,Z可以是一个矩阵,我们将我们的数据表示成一个向量,那么自然也会得到我们的Sigmoid矩阵函数,这里的棘突过程就不解释了

  • 可以将z表示成
    - w表示权重,x表示我们输入的数据值在这里插入图片描述

  • 我们一般是将g(z)=0.5 作为我们划分的依据,既是如果只是大于0.5 那么我们就将其划分为1类,相反就是为0类(就是不同的另一类)

  • 如何求我们的这些参数(权重等参数),又将是我们面临的问题所以这里就会引入我们的代价函数。

代价函数 Cost Function

  • 这里我们使用的交叉熵的代价函数
  • 这里不会具体的研究这里公式的由来,只会大致的了解就好了,这里的a就是相当于z

在这里插入图片描述

  • 而本文所使用的就是利用相反的公式:
    在这里插入图片描述
  • 比较两个公式可以看出,# 只是一个是用数值的形式给出,一个使用向量的形式给出来的,但是其实都是一样的,这里之所以给出不同的,就是方面大家的理解。了解公式的多样性,但是都是表达的差不多意思。只是没有负号 #
  • 上面公式,我们所用到的就是梯度下降算法,而在这里我们多采用的就是梯度上升算法。
  • 梯度上升法是求函数的局部最大值。因此,对比梯度下降法,其几何意义和很好理解,那就是:算法的迭代过程是一个“上坡”的过程,每一步选择坡度变化率最大的方向往上走,这个方向就是函数在这一点梯度方向(注意不是反方向了)。最后随着迭代的进行,梯度还是不断减小,最后趋近与零。

Gradient ascent algorithm 梯度上升算法

  • 利用python代码来实现,梯度上升测试函数
  • 我们的函数例子为
    在这里插入图片描述
  • 我们利用梯度上升算法就是求该公式取得极大值是的,x的值,代码如下:
'''
函数说明:梯度上升算法测试函数
求函数f(x) = -x^2 + 4x的极大值

'''
def Gradient_Ascent_test():
    # 表示f(x)的导数
    def f_prime(x_old):
        # 这就是我们所要计算的公式
        return -2 * x_old + 4
    # 初始值,给一个小于x_new的值
    x_old = -1
    # 梯度上升算法的初始值,即从(0,0)开始
    x_new = 0
    # 步长就是学习速率,控制更新的快慢
    alpha = 0.01
    # 精度,就是更新的阈值
    presision = 0.000001
    while abs(x_new - x_old) > presision:
        x_old = x_new
        x_new = x_old + alpha * f_prime(x_old)
    print(x_new)

if __name__ == '__main__':
    Gradient_Ascent_test()

输出的即结果为:
在这里插入图片描述

  • 有分析可知,该函数在x=2处,取得极大值,而我们利用梯度上升算法所取得的近视值已经很接近2了,所以我哦们的结果还是很满意的了。

在这里一些梯度上升算法的迭代公式就不在一步步的推导了。

三、python3.7 实战

1. 数据准备

# -*- coding:UTF-8 -*-
import matplotlib.pyplot as plt
import numpy as np



def loadDataSet():
    # 创建数据列表,用来放入我们的数据
    dataMat = []
    # 该列表就是用来存放我们的标签的
    labelMat = []
    # 读取我们的数据集txt文件
    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]))
    # 关闭数据集文件
    fr.close()
    # 返回我们的数据集列表和标签列表
    return dataMat, labelMat

'''
下面就是我们事先数据可视化的步骤
plotDataSet函数就是实现数据集可视化的

'''
def plotDataSet():
    # 数据集的实例化,也就是加载数据
    dataMat, labelMat = loadDataSet()
    # 将数据转换为有序列的numpy中的array数组
    dataArr = np.array(dataMat)
    # 获取数据的个数,也就是行数
    n = np.shape(dataMat)[0]
    # 下面两个不同的列表就是分别计算正样本和负样本的
    # 正样本
    xcord1 = []; ycord1 = []
    # 负样本
    xcord2 = []; ycord2 = []
    # 根据数据集的标签进行分类
    for i in range(n):
        # 如果标签是1
        if int(labelMat[i]) == 1:
            # 将为1 的放入我们的正样本中
            xcord1.append(dataArr[i,1]); ycord1.append(dataArr[i,2])
        else:
            # 其他,既是为0时放入负样本中
            xcord2.append(dataArr[i,1]); ycord2.append(dataArr[i,2])
    # 绘制绘图框
    fig = plt.figure()
    # 添加子图subplot
    ax = fig.add_subplot(111)
    # 实现正样本的可视化
    ax.scatter(xcord1, ycord1, s = 20, c = 'red', marker = 's',alpha=.5)
    # 实现负样本的可视化
    ax.scatter(xcord2, ycord2, s = 20, c = 'blue',alpha=.5)
    # 设置绘图框的title
    plt.title('DataSet')
    plt.xlabel('x'); plt.ylabel('y')
    plt.show()

if __name__ == '__main__':
    plotDataSet()

实现结果图:
在这里插入图片描述

2. 训练算法

# -*- coding:UTF-8 -*-
import matplotlib.pyplot as plt
import numpy as np


def loadDataSet():
    # 创建数据列表,用来放入我们的数据
    dataMat = []
    # 该列表就是用来存放我们的标签的
    labelMat = []
    # 读取我们的数据集txt文件
    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]))
    # 关闭数据集文件
    fr.close()
    # 返回我们的数据集列表和标签列表
    return dataMat, labelMat

# 定义sigmiod函数
def sigmoid(inx):
    return 1.0/(1 + np.exp(-inx))


'''
下面就是我们的梯度上升算法的实现
gradAscent
'''
def gradAscent(dataMatIn, classLabels):
    # 将数据集转换为numpy的mat
    dataMatrix = np.mat(dataMatIn)
    # 将标签转换成numpy的mat。并且进行转置
    # transpose 就是表示转置
    labelMat = np.mat(classLabels).transpose()
    # 返回dataMatrix的大小。m为行数,n为列数。
    m, n = np.shape(dataMatrix)
    # 移动步长,也就是学习速率,控制更新的幅度。
    alpha = 0.001
    # 最大迭代次数
    maxCycles = 500
    # 权重的初始化为0
    weights = np.ones((n,1))
    for k in range(maxCycles):
        # h就是代表z的含义,梯度上升矢量化公式
        h = sigmoid(dataMatrix * weights)
        error = labelMat - h
        weights = weights + alpha * dataMatrix.transpose() * error
    # 将矩阵转换为数组,返回权重数组
    # 这里的最优权重数组就是所求的最佳的解
    return weights.getA()


if __name__ =='__main__':
    dataMat, labelMat = loadDataSet()
    matrix = gradAscent(dataMat,labelMat)
    print(matrix)

运行结果:
在这里插入图片描述
这里为什么是出现三行数组呢,因为我们的数据集特征是两个,同时一般规定我们默认Xo为1,所以就该出现的是三个权重,Wo,W1,W2。

3. 绘制决策边界 Ploting the decision boundary

# -*- coding:UTF-8 -*-
import matplotlib.pyplot as plt
import numpy as np


def loadDataSet():
    # 创建数据列表,用来放入我们的数据
    dataMat = []
    # 该列表就是用来存放我们的标签的
    labelMat = []
    # 读取我们的数据集txt文件
    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]))
    # 关闭数据集文件
    fr.close()
    # 返回我们的数据集列表和标签列表
    return dataMat, labelMat

# 定义sigmiod函数
def sigmoid(inx):
    return 1.0/(1 + np.exp(-inx))


'''
下面就是我们的梯度上升算法的实现
gradAscent
'''
def gradAscent(dataMatIn, classLabels):
    # 将数据集转换为numpy的mat
    dataMatrix = np.mat(dataMatIn)
    # 将标签转换成numpy的mat。并且进行转置
    # transpose 就是表示转置
    labelMat = np.mat(classLabels).transpose()
    # 返回dataMatrix的大小。m为行数,n为列数。
    m, n = np.shape(dataMatrix)
    # 移动步长,也就是学习速率,控制更新的幅度。
    alpha = 0.001
    # 最大迭代次数
    maxCycles = 500
    # 权重的初始化为0
    weights = np.ones((n,1))
    for k in range(maxCycles):
        # h就是代表z的含义,梯度上升矢量化公式
        h = sigmoid(dataMatrix * weights)
        error = labelMat - h
        weights = weights + alpha * dataMatrix.transpose() * error
    # 将矩阵转换为数组,返回权重数组
    # 这里的最优权重数组就是所求的最佳的解
    return weights.getA()

def plotBestFit(weights):

    # 数据集的实例化,也就是加载数据
    dataMat, labelMat = loadDataSet()
    # 将数据转换为有序列的numpy中的array数组
    dataArr = np.array(dataMat)
    # 获取数据的个数,也就是行数
    n = np.shape(dataArr)[0]
    # 下面两个不同的列表就是分别计算正样本和负样本的
    # 正样本
    xcord1 = []; ycord1 = []
    # 负样本
    xcord2 = []; ycord2 = []
    # 根据数据集的标签进行分类
    for i in range(n):
        # 如果标签是1
        if int(labelMat[i]) == 1:
            # 将为1 的放入我们的正样本中
            xcord1.append(dataArr[i,1]); ycord1.append(dataArr[i,2])
        else:
            # 其他,既是为0时放入负样本中
            xcord2.append(dataArr[i,1]); ycord2.append(dataArr[i,2])
    # 绘制绘图框
    fig = plt.figure()
    # 添加子图subplot
    ax = fig.add_subplot(111)
    # 实现正样本的可视化
    ax.scatter(xcord1, ycord1, s = 20, c = 'red', marker = 's')
    # 实现负样本的可视化
    ax.scatter(xcord2, ycord2, s = 20, c = 'blue')
    x = np.arange(-3.0, 3.0, 0.1)
    y = (-weights[0]- weights[1] *x)/ weights[2]
    ax.plot(x,y)
    # 设置绘图框的title
    plt.title('DataSet')
    plt.xlabel('x'); plt.ylabel('y')
    plt.show()

if __name__ == '__main__':
    dataMat, labelMat = loadDataSet()
    weights = gradAscent(dataMat, labelMat)
    plotBestFit(weights)

运行结果:
在这里插入图片描述
这个分类结果相当不错,从上图可以看出,只分错了几个点而已。但是,尽管例子简单切数据集很小,但是这个方法却需要大量的计算(300次乘法)。因此下篇文章将对改算法稍作改进,从而减少计算量,使其可以应用于大数据集上。

四、总结、

逻辑回归的一般步骤:

  • 收集数据:采用任意方法收集数据。
  • 准备数据:由于需要进行距离计算,因此要求数据类型为数值型。另外,结构化数据格式则最佳。
  • 分析数据:采用任意方法对数据进行分析。
  • 训练算法:大部分时间将用于训练,训练的目的是为了找到最佳的分类回归系数。
  • 测试算法:一旦训练步骤完成,分类将会很快。
  • 使用算法:首先,我们需要输入一些数据,并将其转换成对应的结构化数值;接着,基于训练好的回归系数,就可以对这些数值进行简单的回归计算,判定它们属于哪个类别;在这之后,我们就可以在输出的类别上做一些其他分析工作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值