Bootstrap

逻辑回归分类(python实现)

逻辑回归

1.基本概念

在前面学习线性回归时,我们知道可以对一组测试数据来进行预测输出,线性回归模型能不能用来解决分类问题呢,答案是否定的,但是我们可以利用线性回归再配合辅助函数来构建分类器。逻辑回归是基于 S i g m o i d Sigmoid Sigmoid函数,这个函数有很明显的特点。
在这里插入图片描述

x x x>0时, y y y>0.5, x x x<0,时 y y y<0.5,并且 y y y值在左边区域1,右边趋于0。 S i g m o i d Sigmoid Sigmoid公式如下
g ( z ) = 1 1 + e − z ( 1.1 ) g(z)=\frac{1}{1+e^{-z}}\quad\quad\quad(1.1) g(z)=1+ez1(1.1)
在这里插入图片描述

这里有一份已经分好类的数据集,不同颜色代表不同的类别,我么可以很明显的观察到在这两类中间存在这一条分割线,这条线在这里被称作决策边界。我们可以定义这条在决策边界的直线方程为
z = f ( x ( i ) ) = θ 1 x 1 ( i ) + θ 2 x 2 ( i ) + . . . + θ j x j ( i ) ( 1.2 ) z=f(x^{(i)})=\theta_1x_1^{(i)}+\theta_2x_2^{(i)}+...+\theta_jx_j^{(i)}\quad(1.2) z=f(x(i))=θ1x1(i)+θ2x2(i)+...+θjxj(i)(1.2)
这里我用上标 i i i表示第 i i i个样本,用 j j j表示特征维度。虽然决策边界方程已经确定下来了,但是如何使用决策边界来做分类问题呢,根据我们高中所学的方程思想,在决策边界上的数据点对于1.2式的值会等于0,在决策边界上的数据点对于1.2式会大于0,对于决策边界下的数据点对于1.2式会小于0。若预测z值大于0为1类,z值小于0为0类,这样就很好的解决了二分类问题。目前的问题只需要将z值转化为0/1值
z = f ( x ( i ) ) = θ T X ( 1.3 ) z=f(x^{(i)})=\theta^TX\quad\quad\quad(1.3) z=f(x(i))=θTX(1.3)
其中X是 m ∗ n m*n mn的矩阵
X = [ x 1 ( 1 ) x 1 ( 2 ) . . . x 1 ( j ) x 2 ( 1 ) x 2 ( 2 ) . . . x 2 ( j ) . . . x i ( 1 ) x i ( 2 ) . . . x i ( j ) ] ( 1.4 ) X=\begin{bmatrix}x_1^{(1)}&x_1^{(2)}&...&x_1^{(j)}\\x_2^{(1)}&x_2^{(2)}&...&x_2^{(j)}\\.\\.\\.x_i^{(1)}&x_i^{(2)}&...&x_i^{(j)} \end{bmatrix}(1.4) X= x1(1)x2(1)...xi(1)x1(2)x2(2)xi(2).........x1(j)x2(j)xi(j) (1.4)
观察上面的sigmoid辅助函数函数的特性。令p=g(z),它可以将z值转化为一个接近于0或1的p值,
p = 1 1 + e − z ( 1.5 ) p=\frac{1}{1+e^{-z}}\quad\quad(1.5) p=1+ez1(1.5)
根据上式1.5可以将p视为类后验概率估计P(y=1|x),由于类别标签不是1就是0,所以类别0的后验概率也可以得出(此句来自西瓜书p59,目前还未深究)
P ( y = 1 ∣ x ) = p P ( y = 0 ∣ x ) = 1 − p ( 1.6 ) P(y=1|x)=p\quad\quad\quad P(y=0|x)=1-p\quad(1.6) P(y=1∣x)=pP(y=0∣x)=1p(1.6)
将公式1.6一般化
P ( y ∣ x ) = { p if  y = 1 1 − p if  y = 0 ( 1.7 ) P(y|x)=\begin{cases} p & \text{if } y = 1 \\ 1-p & \text{if } y = 0 \end{cases} \quad\quad(1.7) P(yx)={p1pif y=1if y=0(1.7)
分段函数不好计算,继续转换
P ( y ∣ x ) = p y ( 1 − p ) ( 1 − y ) ( 1.8 ) P(y|x)=p^y(1-p)^{(1-y)}\quad\quad(1.8) P(yx)=py(1p)(1y)(1.8)
当然只是一个样本的类别后验概率,对于训练数据集中有m个数据样本,采用极大似然法计算整个样本的总后验概率
P 总 = P ( y 1 ∣ x 1 ) P ( y 1 ∣ x 1 ) . . . P ( y m ∣ x m ) = ∏ i = 1 m P ( y i ∣ x i ) ( 1.9 ) P_总=P(y_1|x_1)P(y_1|x_1)...P(y_m|x_m)\\=\prod_{i=1}^mP(y_i|x_i)\quad\quad(1.9) P=P(y1x1)P(y1x1)...P(ymxm)=i=1mP(yixi)(1.9)
由于1.9式中连乘容易造成结果下溢,常采用对数似然
l n ( P 总 ) = ∑ i = 1 m y i l n ( p ) + ( 1 − y i ) l n ( 1 − p ) ) ( 1.10 ) ln(P_总)=\sum_{i=1}^my_iln(p)+(1-y_i)ln(1-p))\quad(1.10) ln(P)=i=1myiln(p)+(1yi)ln(1p))(1.10)
得到式1.10后,我们就可以开始定义损失函数,损失函数是用来衡量模型预测值与真实值的差距,我们希望这种差距越小越好,式1.10中计算出来的结果是训练集总后验概率的极大似然,我们希望这个概率越大越好,与损失函数理念违背,加个负号后就与损失函数理念相符,所以这里的损失函数定义为
J ( θ ) = − l n ( P 总 ) = ∑ i = 1 m − y i l n ( p ) − ( 1 − y i ) l n ( 1 − p ) ) ( 1.11 ) J(\theta)=-ln(P_总)=\sum_{i=1}^m-y_iln(p)-(1-y_i)ln(1-p))\quad(1.11) J(θ)=ln(P)=i=1myiln(p)(1yi)ln(1p))(1.11)
损失函数定义出来后,求解最佳参数的决策边界方程转化求解最佳参数 θ \theta θ使得损失函数值最小对这里求解最佳参数方法使用梯度下降法,所谓的梯度就是损失函数对各个参数的偏导向量,其求偏导有

α J α θ j = ∑ i = 1 m ( p − y i ) x i \frac{\alpha J}{\alpha \theta_j}=\sum_{i=1}^{m}(p-y_i)x_i αθjαJ=i=1m(pyi)xi
利用线性回归中接受的梯度下降法求解最佳 θ \theta θ,其中 β \beta β时是学习率
θ j n e w = θ j o l d − β α J o l d α θ j \theta_j^{new}=\theta_j^{old}-\beta\frac{\alpha J^{old}}{\alpha \theta_j} θjnew=θjoldβαθjαJold

2.代码实现

#导入科学计算包
from numpy import *
#导入matplot第三方包
import matplotlib.pyplot as plt
#读取文本文件,创建数据集
def loadDataSet():
    #定义数据集,标签集
    dataMat=[]
    labelMat=[]
    #打开文本文件
    f=open("D:/学习资料\机器学习实战/《机器学习实战》源代码/machinelearninginaction/Ch05/testSet.txt")
    #存储数据集
    for line in f.readlines():
        lineArr=line.strip().split()
        #添加一列全为1的数据
        dataMat.append([1.0,float(lineArr[0]),float(lineArr[1])])
        labelMat.append(int(lineArr[2]))
    return dataMat,labelMat
#定义sigmoid函数
def sigmoid(inx):
    return 1.0/(1+exp(-inx))
#计算梯度
def get_gent(data,label,theta,m):
    return dot(data.T,(sigmoid(dot(data,theta))-label))
#计算损失函数
def get_loss(data,label,theta,m):
    var=ones((m,1))
    print(shape(var))
    return -(label.T*log(sigmoid(dot(data,theta)))+(var-label).T*log(var-sigmoid(dot(data,theta))))
#梯度下降法
def gent_dense(data,label,alpha,epochs):
    #获取数据集形状
    m,n=shape(data)
    # 初始化theta
    theta=ones((n,1))
    #获取损失值
    loss=get_loss(data,label,theta,m)
    #定义存储损失值列表
    loss_list=list()
    # print(loss)
    loss_list.append(loss.tolist()[0][0])
    # 获取梯度
    gent=get_gent(data,label,theta,m)
    #迭代
    for i in range(epochs):
        #获取新的参数
        # print(shape(gent))
        theta=theta-alpha*gent
        #获取梯度
        gent=get_gent(data, label, theta, m)
        #获取损失值
        # print(shape(theta))
        loss=get_loss(data,label,theta,m)
        loss_list.append(loss.tolist()[0][0])
    return theta,loss_list
#绘图
def ploter(data,label,theta,loss_list,epochs):
    # # 设置中文
    plt.rcParams['font.sans-serif'] = ['SimHei']
    plt.rcParams['axes.unicode_minus'] = False
    plt.plot(range(epochs+1),loss_list)
    plt.xlabel("迭代次数")
    plt.ylabel("损失函数值")
    plt.show()

    fig = plt.figure()
    # 创建一个1X1的绘图区域
    ax = fig.add_subplot(111)
    x1=list()
    y1=list()
    x2=list()
    y2=list()
    x3=list()
    for i in range(len(data)):
        if label[i]==0:
            x1.append(data[i][1])
            y1.append((data[i][2]))
        else:
            x2.append((data[i][1]))
            y2.append((data[i][2]))
        x3=data[i][0]
    plt.scatter(x1,y1,color='green')
    plt.scatter(x2, y2, color='red')
    # 创建一个等距离的一维数组,作为X轴的间隔
    x = arange(-3.0, 3.0, 0.1)
    # 划分最佳直线方程
    print(theta.tolist()[0])
    y = (-theta.tolist()[0][0] - theta.tolist()[1][0] * x) / theta.tolist()[2][0]
    plt.plot(x,y)
    plt.show()
#测试
if __name__=='__main__':
    data,label=loadDataSet()
    epchos=500
    theta,loss_list=gent_dense(mat(data),mat(label).T,0.001,epchos)
    print(theta,loss_list)
    ploter(data,label,theta,loss_list,epchos)

损失函数图像,决策边界拟合图像如下

在这里插入图片描述

在这里插入图片描述

可以看出仍然有几个点预测错误,但是这个拟合出来的决策边界还是相当可靠的

3.总结

求解最佳参数的方法不止有梯度下降法,还有牛顿法,BFGS等方法。

参考博客:https://zhuanlan.zhihu.com/p/44591359
参考书籍:《机器学习》周志华 《机器学习实战》Peter

;