目录

1.逻辑斯蒂回归的概念

一、逻辑回归模型的原理与定义(主要思想)

2.什么是Sigmoid函数

2. 逻辑斯蒂回归常用的优化方法和优缺点

2.1优缺点

2.2常用优化方法

3.逻辑斯蒂回归的代码实现

3.1 代码分析

3.2 数据集分类实现

3.3总结


1.逻辑斯蒂回归的概念

一、逻辑回归模型的原理与定义(主要思想)

  Logistic回归也是一种分类方法,用于两分类问题。其基本思想为:(1)寻找合适的假设函数,即分类函数,用以预测输入数据的判断结果;(2)构造代价函数,即损失函数,用以表示预测的输出结果与训练数据的实际类别之间的偏差;(3)最小化代价函数,从而获取最优的模型参数。

        Logistics回归的目的是寻找一个非线性函数Sigmoid的最佳拟合参数,求解过程可以由最优化算法来完成。在最优化算法中,最常用的就是梯度上升算法,而梯度上升算法又可以简化为随机梯度上升算法。

        随机梯度上升算法与梯度上升算法的效果相当,但占用更少的计算资源。此外,随机梯度上升是一个在线算法,它可以在新数据到来时就完成参数更新,而不需要重新读取整个数据集来进行批处理运算。

定义:
在线性回归模型的基础上,使用Sigmoid函数,将线性模型的结果压缩到[0,1]之间,使其拥有概率意义,它可以将任意输入映射到[0,1]区间,实现值到概率转换。

2.什么是Sigmoid函数

基本公式如下:

逻辑斯蒂回归对数似然求解 逻辑斯蒂回归推导_数据集

函数中t无论取什么值,其结果都在[0,1]的区间内,回想一下,一个分类问题就有两种答案,一种是“是”,一种是“否”,那0对应着“否”,1对应着“是”,那又有人问了,你这不是[0,1]的区间吗,怎么会只有0和1呢?这个问题问得好,我们假设分类的阈值是0.5,那么超过0.5的归为1分类,低于0.5的归为0分类,阈值是可以自己设定的。

接下来我们把aX+b带入t中就得到了我们的逻辑回归的一般模型方程:

逻辑斯蒂回归对数似然求解 逻辑斯蒂回归推导_数据_02

结果P也可以理解为概率,换句话说概率大于0.5的属于1分类,概率小于0.5的属于0分类,这就达到了分类的目的。

2. 逻辑斯蒂回归常用的优化方法和优缺点

2.1优缺点

优点:

LR能以概率的形式输出结果,而非只是0,1判定。
LR的可解释性强,可控度高(你要给老板讲的嘛…)。
训练快,feature engineering之后效果赞。
因为结果是概率,可以做ranking model

缺点:

不能用Logistic回归去解决非线性问题,因为Logistic的决策面试线性的;
对多重共线性数据较为敏感;
很难处理数据不平衡的问题;
准确率并不是很高,因为形式非常的简单(非常类似线性模型),很难去拟合数据的真实分布
逻辑回归本身无法筛选特征,有时会用gbdt来筛选特征,然后再上逻辑回归

2.2常用优化方法

2.1 一阶方法
梯度下降、随机梯度下降、mini 随机梯度下降降法。随机梯度下降不但速度上比原始梯度下降要快,局部最优化问题时可以一定程度上抑制局部最优解的发生。

2.2 二阶方法:牛顿法、拟牛顿法:
这里详细说一下牛顿法的基本原理和牛顿法的应用方式。牛顿法其实就是通过切线与x轴的交点不断更新切线的位置,直到达到曲线与x轴的交点得到方程解。在实际应用中我们因为常常要求解凸优化问题,也就是要求解函数一阶导数为0的位置,而牛顿法恰好可以给这种问题提供解决方法。实际应用中牛顿法首先选择一个点作为起始点,并进行一次二阶泰勒展开得到导数为0的点进行一个更新,直到达到要求,这时牛顿法也就成了二阶求解问题,比一阶方法更快。我们常常看到的x通常为一个多维向量,这也就引出了Hessian矩阵的概念(就是x的二阶导数矩阵)。

缺点:牛顿法是定长迭代,没有步长因子,所以不能保证函数值稳定的下降,严重时甚至会失败。还有就是牛顿法要求函数一定是二阶可导的。而且计算Hessian矩阵的逆复杂度很大。

拟牛顿法: 不用二阶偏导而是构造出Hessian矩阵的近似正定对称矩阵的方法称为拟牛顿法。拟牛顿法的思路就是用一个特别的表达形式来模拟Hessian矩阵或者是他的逆使得表达式满足拟牛顿条件。主要有DFP法(逼近Hession的逆)、BFGS(直接逼近Hession矩阵)、 L-BFGS(可以减少BFGS所需的存储空间)。
 

3.逻辑斯蒂回归的代码实现

3.1 代码分析

        下面这段代码是梯度上升算法的具体实现。loadDataSet()的主要功能是打开文本文件testSet.txt并逐行读取。每行前两个值分别为X1和X2,第三个值是数据对应的类别标签。此外,为了方便计算,该函数还将X0的值设置为1.0。接下来是sigmoid()函数。梯度上升算法的实际工作是在函数gradAscent()里完成的。该函数有两个参数。第一个参数是dataMathIn,这是一个二维NumPy数组,每列分别代表了每个不同的特征,每行则代表每个训练样本。第二个参数是类别标签,它是一个1×100的2行向量。
 

def loadDataSet():
    dataMat = []; labelMat = []
    fr = open('C:/Users/Kano/Desktop/Study/vscode python/Test3/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
 
def sigmoid(inX):
    return 1.0/(1+exp(-inX))
 
def stocGradAscent1(dataMatrix, classLabels, numIter=150):
    m,n = shape(dataMatrix)
    weights = ones(n)   #initialize to all ones
    for j in range(numIter):
        dataIndex = list(range(m))
        for i in range(m):
            alpha = 4/(1.0+j+i)+0.0001    #apha decreases with iteration, does not 
            randIndex = int(random.uniform(0,len(dataIndex)))#go to 0 because of the constant
            h = sigmoid(sum(dataMatrix[randIndex]*weights))
            error = classLabels[randIndex] - h
            weights = weights + alpha * error * dataMatrix[randIndex]
            del(dataIndex[randIndex])
    return weights

下面这一段第一个函数为classifyVector(),它以回归系数和特征向量作为输入来计算对应的Sigmoid值。如果Sigmoid值大于0.5函数返回1,否则返回0。接下来是函数colicTest()。用于打开测试集和训练集,并对数据进行格式化处理的函数。嘎斯函数首先导入训练集,数据的最后一列为类别标签。数据导入之后,使用函数stocGradAscent1()来计算回归系数向量。最后一个函数为multiTest(),其功能是调用函数colicTest()10次并求结果的平均值。
 

def classifyVector(inX, weights):
    prob = sigmoid(sum(inX*weights))
    if prob > 0.5: return 1.0
    else: return 0.0
 
def colicTest():
    frTrain = open('C:/Users/Kano/Desktop/Study/vscode python/Test3/divorceTraining.txt'); frTest = open('C:/Users/Kano/Desktop/Study/vscode python/Test3/divorceTest.txt')
    trainingSet = []; trainingLabels = []
    for line in frTrain.readlines():
        currLine = line.strip().split(';')
        lineArr =[]
        for i in range(54):
            lineArr.append(float(currLine[i]))
        trainingSet.append(lineArr)
        trainingLabels.append(float(currLine[54]))
    trainWeights = stocGradAscent1(array(trainingSet), trainingLabels, 1000)
    errorCount = 0; numTestVec = 0.0
    for line in frTest.readlines():
        numTestVec += 1.0
        currLine = line.strip().split(';')
        lineArr =[]
        for i in range(54):
            lineArr.append(float(currLine[i]))
        if int(classifyVector(array(lineArr), trainWeights))!= int(currLine[54]):
            errorCount += 1
    errorRate = (float(errorCount)/numTestVec)
    print ("the error rate 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 rate is: %f" % (numTests, errorSum/float(numTests)))

3.2 数据集分类实现

        使用一个数据集,离婚数据。他有54个属性,分别是对于伴侣的行为情况进行打分,最后根据这些分类结果给出是否离婚的情况。下面我们大概看一下这些属性信息。

1. 如果我们中的一个人在讨论恶化时道歉,讨论就结束了。
2. 我知道我们可以忽略我们的分歧, 即使事情有时变得艰难。
3. 当我们需要它时,我们可以从一开始就与我的配偶进行讨论并纠正它。
4. 当我与我的配偶讨论时,联系他最终会起作用。
5. 我和妻子在一起的时间对我们来说很特别。
部分数据集如下:

逻辑斯蒂回归对数似然求解 逻辑斯蒂回归推导_数据_03

测试结果

逻辑斯蒂回归对数似然求解 逻辑斯蒂回归推导_逻辑斯蒂回归对数似然求解_04

3.3总结

4. 总结
        通过这次实验了解了如何使用逻辑斯蒂回归对数据集进行训练和分类。也知道了逻辑斯蒂回归的数学原理:它在线性回归的基础上,在特征到结果的映射中加入了一层Sigmoid函数(非线性)映射,即先把特征线性求和,然后使用Sigmoid函数来预测。而Sigmoid函数用于机器学习分类的效果很好。最后带入数据集之后效果还不错,原因应该为:(1)数据集的属性特征值为0~4的数据,比较简单且易于分类,当我使用差异较大或者小数较多的数据集时效果并没有这个好;(2)属性较多,且结果仅有离婚与不离婚两种,更适合Sigmoid函数。相信在之后的学习中会有更多方法来适应不同类的数据集,给出更好的分类效果。