机器学习——逻辑回归(Logistic Regression)

目录

一、 Logistic回归

1.1 概念简述

1.2 Sigmoid函数

1.3 梯度上升法

 二、代码实现

2.1 数据集

2.2 代码实现

 2.3 结果展示:

2.4 改进算法——随机梯度上升

三、总结

3.1 优点

3.2 缺点

3.3 代码改进的好处


一、 Logistic回归

1.1 概念简述

逻辑回归是一种用于解决分类问题的机器学习方法。它是一种基于概率思想的预测分析技术。分类算法 Logistic 回归用于预测分类因变量的似然性。逻辑回归中的因变量是二进制变量,数据编码为 1(是、真、正常、成功等)或 0(否、假、异常、失败等)。

Logistic 回归的目标是发现特征与特定结果的可能性之间的联系。例如,当根据学习的小时数预测学生是否通过考试时,响应变量有两个值:通过和失败。

Logistic 回归模型类似于线性回归模型,不同之处在于 Logistic 回归使用更复杂的成本函数,称为“Sigmoid 函数”或“逻辑函数”而不是线性函数。

1.2 Sigmoid函数

 Sigmoid函数将输入变换为(0,1)上的输出。它将范围(-inf,inf)中的任意输入压缩到区间(0,1)中的某个值。

为了实现Logistic回归分类器,我们在每个特征上都乘以一个回归系数,然后把所有的结果值相加,将这个总和代人Sigmoid函数中,进而得到一个范围在0~1之间的数值。任何大于0.5的数据被分入1类,小于0.5即被归入0类。

通过Sigmoid函数,我们可以将z转换为概率值p,从而判断样本属于哪个类别。Sigmoid函数及图像如下:

   \sigma \left ( z \right ) = \frac{1}{1+e^{-z}}

1.3 梯度上升法

 梯度上升是一种迭代算法,用于寻找函数的局部最大值或全局最大值。它的核心思想是沿着函数梯度的正方向进行迭代更新,以逐步接近最大值点。在每一次迭代中,根据当前位置的梯度方向来更新参数或变量值,使目标函数值增大。

从 P0 开始,计算完该点的梯度,函数就根据梯度移动到下一点 P1。在 P1 点,梯度再次被重新计算,并沿着新的梯度方向移动到 P2 。如此循环迭代,直到满足停止条件。迭代过程中,梯度算子总是保证我们能选取到最佳的移动方向。

 二、代码实现

2.1 数据集

testSet.txt

-0.017612    14.053064    0
-1.395634    4.662541    1
-0.752157    6.538620    0
-1.322371    7.152853    0
0.423363    11.054677    0
0.406704    7.067335    1
0.667394    12.741452    0
-2.460150    6.866805    1
0.569411    9.548755    0
-0.026632    10.427743    0
0.850433    6.920334    1
1.347183    13.175500    0
1.176813    3.167020    1
-1.781871    9.097953    0
-0.566606    5.749003    1
0.931635    1.589505    1
-0.024205    6.151823    1
-0.036453    2.690988    1
-0.196949    0.444165    1
1.014459    5.754399    1
1.985298    3.230619    1
-1.693453    -0.557540    1
-0.576525    11.778922    0
-0.346811    -1.678730    1
-2.124484    2.672471    1
1.217916    9.597015    0
-0.733928    9.098687    0
-3.642001    -1.618087    1
0.315985    3.523953    1
1.416614    9.619232    0
-0.386323    3.989286    1
0.556921    8.294984    1
1.224863    11.587360    0
-1.347803    -2.406051    1
1.196604    4.951851    1
0.275221    9.543647    0
0.470575    9.332488    0
-1.889567    9.542662    0
-1.527893    12.150579    0
-1.185247    11.309318    0
-0.445678    3.297303    1
1.042222    6.105155    1
-0.618787    10.320986    0
1.152083    0.548467    1
0.828534    2.676045    1
-1.237728    10.549033    0
-0.683565    -2.166125    1
0.229456    5.921938    1
-0.959885    11.555336    0
0.492911    10.993324    0
0.184992    8.721488    0
-0.355715    10.325976    0
-0.397822    8.058397    0
0.824839    13.730343    0
1.507278    5.027866    1
0.099671    6.835839    1
-0.344008    10.717485    0
1.785928    7.718645    1
-0.918801    11.560217    0
-0.364009    4.747300    1
-0.841722    4.119083    1
0.490426    1.960539    1
-0.007194    9.075792    0
0.356107    12.447863    0
0.342578    12.281162    0
-0.810823    -1.466018    1
2.530777    6.476801    1
1.296683    11.607559    0
0.475487    12.040035    0
-0.783277    11.009725    0
0.074798    11.023650    0
-1.337472    0.468339    1
-0.102781    13.763651    0
-0.147324    2.874846    1
0.518389    9.887035    0
1.015399    7.571882    0
-1.658086    -0.027255    1
1.319944    2.171228    1
2.056216    5.019981    1
-0.851633    4.375691    1
-1.510047    6.061992    0
-1.076637    -3.181888    1
1.821096    10.283990    0
3.010150    8.401766    1
-1.099458    1.688274    1
-0.834872    -1.733869    1
-0.846637    3.849075    1
1.400102    12.628781    0
1.752842    5.468166    1
0.078557    0.059736    1
0.089392    -0.715300    1
1.825662    12.693808    0
0.197445    9.744638    0
0.126117    0.922311    1
-0.679797    1.220530    1
0.677983    2.556666    1
0.761349    10.693862    0
-2.168791    0.143632    1
1.388610    9.341997    0
0.317029    14.739025    0

2.2 代码实现

函数loadDataSet:用于读取训练数据集,将数据集分为特征矩阵(dataMat)和标签矩阵(labelMat)。

def loadDataSet():  #得到数据矩阵和标签矩阵
    dataMat = []
    labelMat = []
    fr = open(r'E:\机器学习\code\Logistic\testSet.txt')
    for line in fr.readlines():
        lineArr = line.strip().split()  # strip()去除首尾空格,split拆分字符串,默认为空格拆分
        dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])])     # 这里的1.0是x0
        labelMat.append(float(lineArr[2]))
    return dataMat, labelMat

函数sigmoid:计算sigmoid函数值。

def sigmoid(inX):  #sigmoid函数
    return 1.0/(1 + np.exp(-inX))

函数gradAscent:实现梯度上升法,该函数接收数据矩阵、标签矩阵作为输入参数。对回归系数进行梯度上升,获得最佳回归系数。alpha是目标移动的步长。

def gradAscent(dataMatIn,classLabels):  #实现梯度上升算法
    dataMatrix= np.mat(dataMatIn)   #把list数据类型变成矩阵
    labelMat = np.mat(classLabels).transpose()  #transpose是矩阵转置
    m,n=np.shape(dataMatrix)   #行、列
    alpha = 0.001
    maxCycles=500   #迭代次数
    weights = np.ones((n, 1))
    for k in range(maxCycles):
        h = sigmoid(dataMatrix* weights)    #维度100*上31,相当于给每一维都做了sigmoid,这里是预测值,sigmoid(数据矩阵x权重),是0/1给聚类
        # dataMatrix是样本矩阵,每一行代表着一个数据
        error =(labelMat-h)     #梯度上升方向,聚类和真实值的误差
        weights = weights + alpha* dataMatrix.transpose()* error # 维度3*100* 100*1,权重更新的方向
    return weights

 函数plotBestFit:绘制最优拟合直线,展示分类结果。

def plotBestFit(wei):
    import matplotlib.pyplot as plt
    weights = wei   #getA()是将numpy矩阵转化成数组形式,这里删去了
    dataMat, labelMat = loadDataSet()
    dataArr = np.array(dataMat)     #转成array类型
    n= np.shape(dataArr)[0]     #shape是维度,[0]代表维度的第一个值
    xcord1 =[];ycord1 =[]
    xcord2 =[];ycord2 =[]
    for i in range(n):  #根据标签0/1把数据分到两个矩阵数组中
        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')
    #plt.scatter(x,y,c="b",label=scatter figure”)x: x轴上的数值 y: y轴上的数值 c: 散点图中的标记的颜色 label: 标记图形内容的标签文本
    x= np.arange(-3.0,3.0,0.1)      #生成一维数组,从-3到3步长0.1
    y =(-weights[0]-weights[1]*x)/weights[2]   
    #w0 + w1x1+ w2y=0 ->y=(-w0-w1x1)/w2 z=0时,sigmoid函数取中间值,也就是0.5
    #分界线是w0x0 + w1x1 + w2x2=0,这里要画关于x1和x2的分界线所以这一步是求在x1不断变化时x2的值
    ax.plot(x,y)
    plt.xlabel('X1');plt.ylabel('X2');
    plt.show()

 2.3 结果展示:

plotBestFit(weights1.getA())

运行结果:

        回归系数:

       [[4.12414349]
        [0.48007329]
        [-0.6168482]]

上图可见,分类结果还是很明显的,总体来说得到的结果和分割线都算不错的。

2.4 改进算法——随机梯度上升

1.梯度上升算法在每次更新回归系数时,都需要遍历整个数据集,该法在处理小数据集时尚可,但如果数据集很庞大,那么该法的计算复杂度就太高了。因此,一种改进的方法是一次仅对一个样本点来更新回归系数,该法称为随机梯度上升算法。

2.随机梯度上升算法中,有些系数需要迭代很多次才能达到稳定值,且在大的系数波动停止后,还有一些小的周期性波动,产生这种现象的原因是存在一些不能正确分类的样本点,即数据集并不是线性可分的,在每次迭代时候这些样本点就会引发系数的剧烈改变。而我们期望的算法是能够避免这种来回的波动,从而收敛到某个值。

代码如下:

def stocGradAscent(dataMatrix,classLabels,numIter=150):#随机梯度上升算法,来一个更新一次权重系数
    m,n = np.shape(dataMatrix)
    weights = np.ones(n)
    for j in range(numIter):
        dataIndex= list(range(m))
        for i in range(m):
            alpha =4/(1.0+j+i)+0.01
            randIndex= int(np.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

weights =stocGradAscent(np.array(dataArr),labelMat,)

plotBestFit(weights)

运行结果:

        回归系数:

[13.84580515  0.86998876 -2.13468138]

对比前面的结果图,可以明显看出有一定的改进。

三、总结

3.1 优点

模型简单:Logistic回归的模型结构简单,易于理解和实现。
速度快:Logistic回归的计算速度相对较快,适合处理大量数据。
适应性:Logistic回归可以处理线性可分问题,对于某些场景具有较好的表现。
易于更新:Logistic回归模型可以容易地更新,吸收新的数据和特征。
稳定性:Logistic回归对异常值和不稳定数据具有一定的鲁棒性。减小极端情况的影响

3.2 缺点

适应性局限:Logistic回归是一个弱分类器,其对数据和场景的适应能力有限,不如决策树等算法强大。仅仅适应于线性分布
特征限制:Logistic回归在处理高维度特征时,表现不如其他算法,如支持向量机等。
无法处理非线性问题:Logistic回归本身仅适用于线性可分问题,处理非线性问题需要借助核技巧等方法。
参数敏感:Logistic回归的参数选择和调整较为复杂,容易受到数据影响,需要多次迭代和调参。
过拟合风险:Logistic回归有可能出现过拟合现象,需要采用特征选择、正则化等方法降低过拟合风险。

3.3 代码改进的好处

一是altha在每次迭代的时候都会调整,缓解了数据波动;

二是通过随机选取样本来更新回归系数,减少周期性的波动。

  • 15
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值