logistic回归

一、回归与分类

回归思想:假设现有一些数据点,用一条直线对这些点进行拟合(该线称为最佳拟合线),这个拟合过程就称为回归

利用logistic回归进行分类的思想:根据现有的数据对分类边界建立回归公式,以此进行分类

二 、Logistic回归的一般过程

(1) 收集数据:采用任意方法收集数据。

(2) 准备数据:由于需要进行距离计算,因此要求数据类型为数值型。另外,结构化数据格式则最佳。

(3) 分析数据:采用任意方法对数据进行分析。

(4) 训练算法:大部分时间将用于训练,训练的目的是为了找到最佳的分类回归系数。

(5) 测试算法:一旦训练步骤完成,分类将会很快。

(6) 使用算法:首先,我们需要输入一些数据,并将其转换成对应的结构化数值; 接着,基于训练好的回归系数就可以对这些数值进行简单的回归计算,判定它们属于哪个类别;在这之后,我们就可以在输出的类别上做一些其他分析工作。

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

3.1、Sigmoid函数看成是一个映射函数或者非线性变换函数,通过变换是的当前的一个值转换成概率,由值转换成概率,就将回归问题转为分类问题 。

3.2 、Sigmoid函数的具体计算公式及图像:

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

3.3 总结线性回归与logistic回归

 四、确定最佳回归系数

sigmoid函数让我们确定了分类函数,而函数输入z的由公式得:z=w0x0+w1x1+...+wnxn,记为z = wTx+b 。

其中Sigmoid函数的输入值为z、向量x是分类器的输入数据,向量w是找到的最佳系数,b为常数。

因此我们的任务就变成如何确认最佳参数。

4.1、训练算法--梯度上升法

  • 梯度上升法基于的思想是:要找到某函数的 最大值,最好的方法是沿着该函数的梯度方向探寻。如果梯度记为∇,则函数f(x,y)的梯度由 下式表示:

       这个梯度意味着要沿x的方向移动 ,沿y的方向移动 。其中,函数f(x,y) 必须要在待计算的点上有定义并且可微。

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

        梯度上升算法沿梯度方向移动了一步。可以看到,梯度算子总是指向函数值增长最快的方向。这里所说的是移动方向,而未提到移动量的大小。该量值称为步长,记做α。用向 量来表示的话,梯度上升算法的迭代公式如下:。 该公式将一直被迭代执行,直至达到某个停止条件为止,比如迭代次数达到某个指定值或算 法达到某个可以允许的误差范围。

  • 梯度下降算法

        它与这里的梯度上升算法是一样的,只是公式中的加法需要变成减法。因此,对应的公式可以写成:,梯度上升算法用来求函数的最大值,而梯度下降算法用来求函数的最小值。

4.2 训练算法--随机梯度上升法

      梯度上升算法在每次更新回归系数时都需要遍历整个数据集,该方法在处理100个左右的数 据集时尚可,但如果有数十亿样本和成千上万的特征,那么该方法的计算复杂度就太高了。一种 改进方法是一次仅用一个样本点来更新回归系数,该方法称为随机梯度上升算法。由于可以在新 样本到来时对分类器进行增量式更新,因而随机梯度上升算法是一个在线学习算法。与“在线学习”相对应,一次处理所有数据被称作是“批处理”。

4.3 小结

  • 梯度上升算法:每次更新回归系数所有样本都参与。

        优点:分类准确,获取全局最优解
        缺点:当样本比较多时,训练速度特别慢
        适用场合:样本较少的数据集

  • 随机梯度下降法:每次更新回归系数只有一个样本参与。

       优点:训练速度很快
       缺点:准确率会降低,并不是朝着整体最优方向进行,容易获取到局部最优解
       适用场合:样本非常多的数据集

 五、简单的例子

    5.1 数据集准备  (0,1二分类问题)

     有115个样本点,每个点包含两个数值型特征:X1和X2。在此数据集上,通过使用梯度上升法找到最佳回归系数,也就是拟合出Logistic回归模型的最佳参数。

5.2  打开文件按行读取数据集并绘制图像

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

# 绘制数据集
def showData():
    dataMat, labelMat = loadDataSet()                      # 加载数据集,标签
    dataArr = np.array(dataMat)                               # 转换成umPy的数组
    n = np.shape(dataArr)[0]                                  # 获取数据总数
    xcord1 = []; ycord1 = []                               # 存放正样本
    xcord2 = []; ycord2 = []                               # 存放负样本
    for i in range(n):                                     # 依据数据集的标签来对数据进行分类
        if int(labelMat[i]) == 1:                          # 数据的标签为1,表示为正样本
            xcord1.append(dataArr[i, 1]); ycord1.append(dataArr[i, 2])
        else:                                              # 否则,若数据的标签不为1,表示为负样本
            xcord2.append(dataArr[i, 1]); ycord2.append(dataArr[i, 2])
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.scatter(xcord1, ycord1, s=15, c='red')             # 绘制正样本
    ax.scatter(xcord2, ycord2, s=15, c='green', marker='s')  # 绘制负样本
    plt.title('DateSet')                                   # 标题
    plt.xlabel('X1'); plt.ylabel('X2')                     # x,y轴的标签
    plt.show()

 

 5.3 使用梯度上升找最佳参数并绘制决策边界

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

# 梯度上升算法
def gradAscent(dataMatIn, classLabels):                            # dataMatIn数据集、classLabels数据标签
    dataMatrix = np.mat(dataMatIn)                                    # 转换为NumPy矩阵
    labelMat = np.mat(classLabels).transpose()                        # 转换为NumPy矩阵,并且矩阵转置
    m, n = np.shape(dataMatrix)                                       # 获取数据集矩阵的大小,m为行数,n为列数
    alpha = 0.001                                                  # 目标移动的步长
    maxCycles = 500                                                # 迭代次数
    weights = np.ones((n, 1))                                         # 权重初始化为1
    for k in range(maxCycles):                                     # 重复矩阵运算
        h = sigmoid(dataMatrix * weights)                          # 矩阵相乘,计算sigmoid函数
        error = (labelMat - h)                                     # 计算误差
        weights = weights + alpha * dataMatrix.transpose() * error # 矩阵相乘,更新权重
    return weights



# 获得回归系数
dataMat, labelMat = loadDataSet()
weigths = gradAscent(dataMat, labelMat)
print("w0: %f, w1: %f, W2: %f" % (weigths[0], weigths[1], weigths[2]))
# 绘制数据集和Logistic回归最佳拟合直线
def plotBestFit(weights):
    dataMat, labelMat = loadDataSet()                      # 加载数据集,标签
    dataArr = np.array(dataMat)                               # 转换成umPy的数组
    n = np.shape(dataArr)[0]                                  # 获取数据总数
    xcord1 = []; ycord1 = []                               # 存放正样本
    xcord2 = []; ycord2 = []                               # 存放负样本
    for i in range(n):                                     # 依据数据集的标签来对数据进行分类
        if int(labelMat[i]) == 1:                          # 数据的标签为1,表示为正样本
            xcord1.append(dataArr[i, 1]); ycord1.append(dataArr[i, 2])
        else:                                              # 否则,若数据的标签不为1,表示为负样本
            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 = np.arange(-3.0, 3.0, 0.1)                             # x区间
    y = (-weights[0] - weights[1] * x) / weights[2]        # 最佳拟合直线
    ax.plot(x, y)
    plt.title('BestFit')                                   # 标题
    plt.xlabel('X1'); plt.ylabel('X2')                     # x,y轴的标签
    plt.show()

# 运行画出图
dataMat, labelMat = loadDataSet()
weigths = gradAscent(dataMat, labelMat)
plotBestFit(weigths.getA())
print("w0: %f, w1: %f, W2: %f" % (weigths[0], weigths[1], weigths[2]))

 

 5.4 优化算法改进--使用随机梯度上升找最佳参数并绘制决策边界

# 随机梯度上升算法
def stocGradAscent0(dataMatrix, classLabels):              # dataMatIn数据集、classLabels数据标签
    m, n = np.shape(dataMatrix)                               # 获取数据集矩阵的大小,m为行数,n为列数
    alpha = 0.01                                           # 目标移动的步长
    weights = np.ones(n)                                      # 所以初始化为1
    for i in range(m):                                     # 重复矩阵运算
        h = sigmoid(sum(dataMatrix[i] * weights))          # 矩阵相乘,计算sigmoid函数
        error = classLabels[i] - h                         # 计算误差
        weights = weights + alpha * error * dataMatrix[i]  # 矩阵相乘,更新权重
    return weights
# 运行测试代码
dataMat, labelMat = loadDataSet()
weigths = stocGradAscent0(np.array(dataMat), labelMat)
plotBestFit(weigths)
print("w0: %f, w1: %f, W2: %f" % (weigths[0], weigths[1], weigths[2]))


 

 

 随机梯度上升算法在上述数据集上的执行结果,最佳拟合直线并非最佳分类线,可以看出拟合曲线出现了很大的偏差。

 5.5 优化算法改进--使用改进随机梯度上升找最佳参数并绘制决策边界

 # 改进的随机梯度上升算法
def stocGradAscent1(dataMatrix, classLabels, numIter=150):  # dataMatIn数据集、classLabels数据标签、numIter迭代次数
    m, n = np.shape(dataMatrix)                                # 获取数据集矩阵的大小,m为行数,n为列数
    weights = np.ones(n)                                       # 所以初始化为1
    for j in range(numIter):
        dataIndex = list(range(m))                          # 创建数据下标列表
        for i in range(m):
            alpha = 4 / (1.0 + j + i) + 0.0001              # apha目标移动的步长,每次迭代调整
            randIndex = int(random.uniform(0, len(dataIndex)))  # 随机选取更新样本
            h = sigmoid(sum(dataMatrix[randIndex] * weights))   # 矩阵相乘,计算sigmoid函数
            error = classLabels[randIndex] - h                  # 计算误差
            weights = weights + alpha * error * dataMatrix[randIndex]  # 矩阵相乘,更新权重
            del (dataIndex[randIndex])                                 # 删除已使用过的样本
    return weights
# 测试
dataMat, labelMat = loadDataSet()
weigths = stocGradAscent1(np.array(dataMat), labelMat)
plotBestFit(weigths)
print("w0: %f, w1: %f, W2: %f" % (weigths[0], weigths[1], weigths[2]))

 

 

六 、实验

使用 Logistic 回归来预测患有疝病的马的存活问题。

6.1准备数据:处理数据中的缺失值

horseColicTraining.txt

horseColicTest.txt

6. 2、测试算法:使用改进随机梯度上升算法进行分类

def colicTest1():
    # 读取测试集和训练集,并对数据进行格式化处理
    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 = gradAscent(np.array(trainingSet), trainingLabels)
    errorCount = 0  # 错误数
    numTestVec = 0.0
    for line in frTest.readlines():  # 遍历每行数据
        numTestVec += 1.0  # 测试集数量加1
        currLine = line.strip().split('\t')
        lineArr = []
        for i in range(21):
            lineArr.append(float(currLine[i]))
        if int(classifyVector(np.array(lineArr), trainWeights)) != float(currLine[21]):
            errorCount += 1  # 预测结果与真值不一致,错误数加1
    errorRate = (float(errorCount) / numTestVec)  # 计算错误率
    print("测试的错误率为: %f" % errorRate)
    return errorRate

# 求结果的平均值
def multiTest():
    numTests = 10
    errorSum = 0.0
    for k in range(numTests):
        errorSum += colicTest1()
    print("在 %d 迭代之后, 平均错误率为: %f" % (numTests, errorSum / float(numTests)))

multiTest()

 

6.3 实验小结

      在本次实验中,对于数据集没有处理。由于testSet.txt放入文件集存入是的格式有问题,导致代码无法运行,后去去掉多余的空格就可以了。logistic回归问题就是概率分类问题,从线性回归到logistic回归(拟合出一条分类的直线)。知道了logistic回归问题与分类之间的联系,一步一步地了解logistic回归是如何实现以及原理,以及算法训练的改进。这些探索的过程都让我收获很多。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cpp_1211

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值