Logistic回归

简介

机器学习的回归(Regression)和分类(Classification)是两种常见的预测任务,它们在目标和方法上有一些关键区别:

1、目标的性质:

回归:旨在预测一个连续的数值。例如,预测房价、温度或者产品的销售量。
分类:旨在将实例分配到预定义的类别中。例如,判断邮件是否为垃圾邮件、识别图片中的物体1类别(如猫、狗等)。
2、输出类型:

回归:输出是一个连续的数值,可以是任何实数。
分类:输出是类别标签,通常为离散的集合(如“是”或“否”,“红色”、“蓝色”、“绿色”等)。
3、评估指标:

回归:通常使用均方误差(Mean Squared Error,MSE)、均方根误差(Root Mean Squared Error,RMSE)或平均绝对误差(Mean Absolute Eroor,MAE)等指标来评估模型性能。
分类:常用的评估指标包括准确率(Accuracy)、精确度(Precision)、召回率(R

一、Logistic回归
1.1什么是Logistic回归
Logistic回归是一种最优化算法。用一条直线对一些数据点进行拟合的过程被称为回归。利用Logistic回归进行分类的主要思想是:根据现有数据利用Logistic回归生成最佳拟合线,并以此作为数据的分类边界线。逻辑回归假设数据服从伯努利分布,通过极大似然估计的方法,运用梯度下降来求解参数,来达到数据二分类的目的。

1.2线性回归函数
线性回归函数的模型

1.3逻辑函数(Sigmoid函数)
若要处理的是二分类问题,我们期望的函数输出会是0或1,类似于单位阶跃函数,可是该函数是不连续的,不连续不可微。

因此我们换一个函数——Sigmoid函数,当x=0时,y为0.5;随着x的增大,y值趋近于1,随着x的减小,y趋近于0,当横坐标足够大时,Sigmoid函数就会看起来像一个阶跃函数。Sigmoid函数的值域在(0,1)之间,而概率P也是在0到1之间,因此我们可以把Sigmoid的值域和概率联系起来

1.4Logistic回归函数 

1.5Logistic回归的优缺点
优点

(1)对率函数任意阶可导,具有很好的数学性质,许多现有的数值优化算法都可以用来求最优解,训练速度快;

(2)简单易理解,模型的可解释性非常好,从特征的权重可以看到不同的特征对最后结果的影响;

(3)适合二分类问题,不需要缩放输入特征;

(4)内存资源占用小,因为只需要存储各个维度的特征值;

(5)直接对分类可能性进行建模,无需事先假设数据分布,避免了假设分布不准确所带来的问题;

(6)以概率的形式输出,而非知识0.1判定,对许多利用概率辅助决策的任务很有用。

缺点

(1)不能用逻辑回归去解决非线性问题,因为Logistic的决策面试线性的;

(2)对多重共线性数据较为敏感;

(3)很难处理数据不平衡的问题;

(4)准确率并不是很高,因为形式非常的简单(非常类似线性模型),很难去拟合数据的真实分布;

(5)逻辑回归本身无法筛选特征,有时会用gbdt来筛选特征,然后再上逻辑回归。

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

三、Logistic回归的实现


 

# -*- coding:UTF-8 -*-
import matplotlib.pyplot as plt
import numpy as np
 
"""
函数说明:加载数据
Returns:
    dataMat - 数据列表
    labelMat - 标签列表
"""
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]))                                #添加标签
    fr.close()                                                            #关闭文件
    return dataMat, labelMat                                            #返回
 
"""
函数说明:绘制数据集
"""
def plotDataSet():
    dataMat, labelMat = loadDataSet()                                    #加载数据集
    dataArr = np.array(dataMat)                                            #转换成numpy的array数组
    n = np.shape(dataMat)[0]                                            #数据个数
    xcord1 = []; ycord1 = []                                            #正样本
    xcord2 = []; ycord2 = []                                            #负样本
    for i in range(n):                                                    #根据数据集标签进行分类
        if int(labelMat[i]) == 1:
            xcord1.append(dataArr[i,1]); ycord1.append(dataArr[i,2])    #1为正样本
        else:
            xcord2.append(dataArr[i,1]); ycord2.append(dataArr[i,2])    #0为负样本
    fig = plt.figure()
    ax = fig.add_subplot(111)                                            #添加subplot
    ax.scatter(xcord1, ycord1, s = 20, c = 'black', marker = 's',alpha=.5)#绘制正样本
    ax.scatter(xcord2, ycord2, s = 20, c = 'red',alpha=.5)            #绘制负样本
    plt.title('DataSet')                                                #绘制title
    plt.xlabel('x1'); plt.ylabel('x2')                                    #绘制label
    plt.show()                                                            #显示
 
if __name__ == '__main__':
    plotDataSet()

训练算法

"""
函数说明:sigmoid函数
Parameters:
    inX - 数据
Returns:
    sigmoid函数
"""
def sigmoid(inX):
    return 1.0 / (1 + np.exp(-inX))
 
 
"""
函数说明:梯度上升算法
Parameters:
    dataMatIn - 数据集
    classLabels - 数据标签
Returns:
    weights.getA() - 求得的权重数组(最优参数)
"""
def gradAscent(dataMatIn, classLabels):
    dataMatrix = np.mat(dataMatIn)                                        #转换成numpy的mat
    labelMat = np.mat(classLabels).transpose()                            #转换成numpy的mat,并进行转置
    m, n = np.shape(dataMatrix)                                            #返回dataMatrix的大小。m为行数,n为列数。
    alpha = 0.001                                                        #移动步长,也就是学习速率,控制更新的幅度。
    maxCycles = 500                                                        #最大迭代次数
    weights = np.ones((n,1))
    for k in range(maxCycles):
        h = sigmoid(dataMatrix * weights)                                #梯度上升矢量化公式
        error = labelMat - h
        weights = weights + alpha * dataMatrix.transpose() * error
    return weights.getA()                                                #将矩阵转换为数组,返回权重数组

分析数据

# 绘制数据集和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()
 
 
if __name__ == '__main__':
    weights = gradAscent(dataMat, labelMat)
    plotBestFit(weights)

训练算法:随机梯度上升

# 随机梯度上升算法
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]))

实例:从疝气病症预测病马的死亡率

测试算法:

def classifyVector(inX, weights):
    prob = sigmoid(sum(inX*weights))
    if prob > 0.5: return 1.0 
    else: return 0.0
def colicTest():
    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 = stocGradAscent1(np.array(trainingSet), trainingLabels, 1000)    #得到最佳回归系数
    errorCount = 0; numTestVec = 0.0
    for line in frTest.readlines():
        numTestVec += 1.0   #计算样本条数
        currLine = line.strip().split('\t')
        lineArr =[]
        for i in range(21):
            lineArr.append(float(currLine[i]))
        if int(classifyVector(np.array(lineArr), trainWeights))!= int(currLine[21]):   #判断是否分类错误
            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() #调用colicTest()函数十次并求结果的平均值
    print ("after %d iterations the average error rate is: %f" % (numTests, errorSum/float(numTests)))
if __name__=='__main__':
    multiTest()

结果:

五、问题及总结
 
问题:为什么与Sigmoid相似的Sign之类的函数不行?

Sign函数,他长得跟Sigmoid函数很类似,也能够将 X 限制在 0 到 1 的范围内。 我们知道,Logistic回归只是在线性回归上增加了一个 g(x) 的限制,而在模型训练的过程中实际上还是对线性回归中的进行训练。我们通过梯度下降在线性回归中进行计算,这就存在一个前提,即损失函数可导。而以 Sign函数为假设函数列出来的损失函数明显存在不可导(左导 = 0,右导 = 1)。而反观 Sigmoid函数,在左右范围内均有导数存在,所以采用Sigmoid函数。

总结

Logistic回归进行分类的主要思想是:根据训练数据利用Logistic回归生成最佳回归系数,并以此进行待测数据的分类。逻辑回归假设数据服从伯努利分布,通过极大似然估计的方法,运用(随机)梯度下降来求解参数,来达到数据二分类的目的。这次实验让我对Logistic回归有了一定的了解和认识,能运用其解决实际问题,但还不能熟练使用,要继续加强对机器学习相关知识的学习。总的来说是一次收获满满的实验。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值