精华内容
下载资源
问答
  • 本文介绍回归模型的原理知识,包括线性回归、多项式回归和逻辑回归,并详细介绍Python Sklearn机器学习库的LinearRegression和LogisticRegression算法及回归分析实例。进入基础文章,希望对您有所帮助。

    欢迎大家来到“Python从零到壹”,在这里我将分享约200篇Python系列文章,带大家一起去学习和玩耍,看看Python这个有趣的世界。所有文章都将结合案例、代码和作者的经验讲解,真心想把自己近十年的编程经验分享给大家,希望对您有所帮助,文章中不足之处也请海涵。Python系列整体框架包括基础语法10篇、网络爬虫30篇、可视化分析10篇、机器学习20篇、大数据分析20篇、图像识别30篇、人工智能40篇、Python安全20篇、其他技巧10篇。您的关注、点赞和转发就是对秀璋最大的支持,知识无价人有情,希望我们都能在人生路上开心快乐、共同成长。

    前一篇文章讲述了数据分析部分,主要普及网络数据分析的基本概念,讲述数据分析流程和相关技术,同时详细讲解Python提供的若干第三方数据分析库,包括Numpy、Pandas、Matplotlib、Sklearn等。本文介绍回归模型的原理知识,包括线性回归、多项式回归和逻辑回归,并详细介绍Python Sklearn机器学习库的LinearRegression和LogisticRegression算法及回归分析实例。进入基础文章,希望对您有所帮助。

    下载地址:

    前文赏析:

    第一部分 基础语法

    第二部分 网络爬虫

    第三部分 数据分析和机器学习

    作者新开的“娜璋AI安全之家”将专注于Python和安全技术,主要分享Web渗透、系统安全、人工智能、大数据分析、图像识别、恶意代码检测、CVE复现、威胁情报分析等文章。虽然作者是一名技术小白,但会保证每一篇文章都会很用心地撰写,希望这些基础性文章对你有所帮助,在Python和安全路上与大家一起进步。


    监督学习(Supervised Learning)包括分类算法(Classification)和回归算法(Regression)两种,它们是根据类别标签分布的类型来定义的。回归算法用于连续型的数据预测,分类算法用于离散型的分布预测。回归算法作为统计学中最重要的工具之一,它通过建立一个回归方程用来预测目标值,并求解这个回归方程的回归系数。

    一.回归

    1.什么是回归

    回归(Regression)最早是英国生物统计学家高尔顿和他的学生皮尔逊在研究父母和子女的身高遗传特性时提出的。1855年,他们在《遗传的身高向平均数方向的回归》中这样描述“子女的身高趋向于高于父母的身高的平均值,但一般不会超过父母的身高”,首次提出来回归的概念。现在的回归分析已经和这种趋势效应没有任何瓜葛了,它只是指源于高尔顿工作,用一个或多个自变量来预测因变量的数学方法。

    在这里插入图片描述

    图1是一个简单的回归模型,X坐标是质量,Y坐标是用户满意度,从图中可知,产品的质量越高其用户评价越好,这可以拟合一条直线来预测新产品的用户满意度。

    在回归模型中,我们需要预测的变量叫做因变量,比如产品质量;选取用来解释因变量变化的变量叫做自变量,比如用户满意度。回归的目的就是建立一个回归方程来预测目标值,整个回归的求解过程就是求这个回归方程的回归系数。

    简言之,回归最简单的定义就是:

    • 给出一个点集,构造一个函数来拟合这个点集,并且尽可能的让该点集与拟合函数间的误差最小,如果这个函数曲线是一条直线,那就被称为线性回归,如果曲线是一条三次曲线,就被称为三次多项回归。

    2.线性回归

    首先,作者引用类似于斯坦福大学机器学习公开课线性回归的例子,给大家讲解线性回归的基础知识和应用,方便大家的理解。同时,作者强烈推荐大家学习原版Andrew Ng教授的斯坦福机器学习公开课,会让您非常受益。

    在这里插入图片描述

    假设存在表1的数据集,它是某企业的成本和利润数据集。数据集中2002年到2016年的数据集称为训练集,整个训练集共15个样本数据。重点是成本和利润两个变量,成本是输入变量或一个特征,利润是输出变量或目标变量,整个回归模型如图2所示。

    在这里插入图片描述

    现建立模型,x表示企业成本,y表示企业利润,h(Hypothesis)表示将输入变量映射到输出变量y的函数,对应一个因变量的线性回归(单变量线性回归)公式如下:

    在这里插入图片描述

    那么,现在要解决的问题是如何求解的两个参数和。我们的构想是选取的参数和使得函数尽可能接近y值,这里提出了求训练集(x,y)的平方误差函数(Squared Error Function)或最小二乘法。

    在回归方程里,最小化误差平方和方法是求特征对应回归系数的最佳方法。误差是指预测y值和真实y值之间的差值,使用误差的简单累加将使得正差值和负差值相互抵消,所采用的平方误差(最小二乘法)如下:

    在这里插入图片描述

    在数学上,求解过程就转化为求一组值使上式取到最小值,最常见的求解方法是梯度下降法(Gradient Descent)。根据平方误差,定义该线性回归模型的损耗函数(Cost Function)为,公式如下:
    在这里插入图片描述

    选择适当的参数让其最小化min,即可实现拟合求解过程。通过上面的这个示例,我们就可以对线性回归模型进行如下定义:根据样本x和y的坐标,去预估函数h,寻求变量之间近似的函数关系。公式如下:

    在这里插入图片描述

    其中,n表示特征数目,表示每个训练样本的第i个特种值,当只有一个因变量x时,称为一元线性回归,类似于;而当多个因变量时,成为多元线性回归。我们的目的是使最小化,从而最好的将样本数据集进行拟合,更好地预测新的数据。

    多项式回归或逻辑回归相关知识将在后面介绍。


    二.线性回归分析

    线性回归是数据挖掘中基础的算法之一,其核心思想是求解一组因变量和自变量之间的方程,得到回归函数,同时误差项通常使用最小二乘法进行计算。在本书常用的Sklaern机器学习包中将调用Linear_model子类的LinearRegression类进行线性回归模型计算。

    1.LinearRegression

    LinearRegression回归模型在Sklearn.linear_model子类下,主要是调用fit(x,y)函数来训练模型,其中x为数据的属性,y为所属类型。sklearn中引用回归模型的代码如下:

    from sklearn import linear_model          #导入线性模型  
    regr = linear_model.LinearRegression()    #使用线性回归  
    print(regr)
    

    输出函数的构造方法如下:

    LinearRegression(copy_X=True,   
    		fit_intercept=True,   
            n_jobs=1,   
            normalize=False) 
    

    其中参数说明如下:

    • copy_X:布尔型,默认为True。是否对X复制,如果选择False,则直接对原始数据进行覆盖,即经过中心化、标准化后,把新数据覆盖到原数据上。
    • fit_intercept:布尔型,默认为True。是否对训练数据进行中心化,如果是True表示对输入的训练数据进行中心化处理,如果是False则输入数据已经中心化处理,后面的过程不再进行中心化处理。
    • n_jobs:整型,默认为1。计算时设置的任务个数,如果设置为-1表示使用所有的CPU。该参数对于目标个数大于1且规模足够大的问题有加速作用。
    • normalize:布尔型,默认为False。是否对数据进行标准化处理。

    LinearRegression类主要包括如下方法:

    在这里插入图片描述

    • fit(X,y[,n_jobs])
      对训练集X,y进行训练,分析模型参数,填充数据集。其中X为特征,y为标记或类属性。
    • predict(X)
      使用训练得到的估计器或模型对输入的X数据集进行预测,返回结果为预测值。数据集X通常划分为训练集和测试集。
    • decision_function(X)
      使用训练得到的估计器或模型对数据集X进行预测。它与predict(X)区别在于该方法包含了对输入数据的类型检查和当前对象是否存在coef_属性的检查,更安全。
    • score(X, y[,]samples_weight)
      返回对于以X为samples、y为target的预测效果评分。
    • get_params([deep])
      获取该估计器(Estimator)的参数。
    • **set_params(params)
      设置该估计器(Estimator)的参数。
    • coef_
      存放LinearRegression模型的回归系数。
    • intercept_
      存放LinearRegression模型的回归截距。

    现在对前面的企业成本和利润数据集进行线性回归实验。完整代码如下:

    # -*- coding: utf-8 -*-
    # By:Eastmount CSDN 2021-07-03
    from sklearn import linear_model     #导入线性模型
    import matplotlib.pyplot as plt       
    import numpy as np
    
    #X表示企业成本 Y表示企业利润
    X = [[400], [450], [486], [500], [510], [525], [540], [549], [558], [590], [610], [640], [680], [750], [900]]
    Y = [[80], [89], [92], [102], [121], [160], [180], [189], [199], [203], [247], [250], [259], [289], [356]]
    print('数据集X: ', X)
    print('数据集Y: ', Y)
    
    #回归训练
    clf = linear_model.LinearRegression() 
    clf.fit(X, Y)
    
    #预测结果
    X2 = [[400], [750], [950]]
    Y2 = clf.predict(X2)
    print(Y2)
    res = clf.predict(np.array([1200]).reshape(-1, 1))[0]   
    print('预测成本1200元的利润:$%.1f' % res) 
    
    #绘制线性回归图形
    plt.plot(X, Y, 'ks')                 #绘制训练数据集散点图
    plt.plot(X2, Y2, 'g-')               #绘制预测数据集直线
    plt.show()
    

    调用sklearn包中的LinearRegression()回归函数,fit(X,Y)载入数据集进行训练,然后通过predict(X2)预测数据集X2的利润,并将预测结果绘制成直线,(X,Y)数据集绘制成散点图,如图3所示。

    在这里插入图片描述

    同时调用代码预测2017年企业成本为1200元的利润为575.1元。注意,线性模型的回归系数会保存在coef_变量中,截距保存在intercept_变量中。clf.score(X, Y) 是一个评分函数,返回一个小于1的得分。评分过程的代码如下:

    print('系数', clf.coef_)
    print('截距', clf.intercept_)
    print('评分函数', clf.score(X, Y))
    
    '''
    系数 [[ 0.62402912]]
    截距 [-173.70433885]
    评分函数 0.911831188777
    '''
    

    在这里插入图片描述

    该直线对应的回归函数为:y = 0.62402912 * x - 173.70433885,则X2[1]=400这个点预测的利润值为75.9,而X1中成本为400元对应的真实利润是80元,预测是基本准确的。


    2.线性回归预测糖尿病

    (1).糖尿病数据集
    Sklearn机器学习包提供了糖尿病数据集(Diabetes Dataset),该数据集主要包括442行数据,10个特征值,分别是:年龄(Age)、性别(Sex)、体质指数(Body mass index)、平均血压(Average Blood Pressure)、S1~S6一年后疾病级数指标。预测指标为Target,它表示一年后患疾病的定量指标。原网址的描述如图4所示:

    在这里插入图片描述

    下面代码进行简单的调用及数据规模的测试。

    # -*- coding: utf-8 -*-
    # By:Eastmount CSDN 2021-07-03
    from sklearn import datasets
    diabetes = datasets.load_diabetes()                           #载入数据  
    print(diabetes.data)                                          #数据  
    print(diabetes.target)                                        #类标  
    print('总行数: ', len(diabetes.data), len(diabetes.target))         
    print('特征数: ', len(diabetes.data[0]))                      #每行数据集维数  
    print('数据类型: ', diabetes.data.shape)                     
    print(type(diabetes.data), type(diabetes.target))     
    

    调用load_diabetes()函数载入糖尿病数据集,然后输出其数据data和类标target。输出总行数442行,特征数共10个,类型为(442L, 10L)。其输出如下所示:

    [[ 0.03807591  0.05068012  0.06169621 ..., -0.00259226  0.01990842 
      -0.01764613] 
     [-0.00188202 -0.04464164 -0.05147406 ..., -0.03949338 -0.06832974 
      -0.09220405] 
      ... 
     [-0.04547248 -0.04464164 -0.0730303  ..., -0.03949338 -0.00421986 
       0.00306441]] 
    [ 151.   75.  141.  206.  135.   97.  138.   63.  110.  310.  101. 
      ... 
    64.   48.  178.  104.  132.  220.   57.] 
    总行数:  442 442 
    特征数:  10 
    数据类型:  (442L, 10L) 
    <type 'numpy.ndarray'> <type 'numpy.ndarray'>         
    

    (2).代码实现
    现在我们将糖尿病数据集划分为训练集和测试集,整个数据集共442行,我们取前422行数据用来线性回归模型训练,后20行数据用来预测。其中取预测数据的代码为diabetes_x_temp[-20:],表示从后20行开始取值,直到数组结束,共取值20个数。

    整个数据集共10个特征值,为了方便可视化画图我们只获取其中一个特征进行实验,这也可以绘制图形,而真实分析中,通常经过降维处理再绘制图形。这里获取第3个特征,对应代码为:diabetes_x_temp = diabetes.data[:, np.newaxis, 2]。完整代码如下:

    # -*- coding: utf-8 -*-
    # By:Eastmount CSDN 2021-07-03
    from sklearn import datasets  
    import matplotlib.pyplot as plt  
    from sklearn import linear_model
    import numpy as np  
    
    #数据集划分
    diabetes = datasets.load_diabetes()                #载入数据  
    diabetes_x_temp = diabetes.data[:, np.newaxis, 2]  #获取其中一个特征  
    diabetes_x_train = diabetes_x_temp[:-20]           #训练样本  
    diabetes_x_test = diabetes_x_temp[-20:]            #测试样本 后20行  
    diabetes_y_train = diabetes.target[:-20]           #训练标记  
    diabetes_y_test = diabetes.target[-20:]            #预测对比标记
    
    #回归训练及预测  
    clf = linear_model.LinearRegression()  
    clf.fit(diabetes_x_train, diabetes_y_train)        #训练数据集  
    pre = clf.predict(diabetes_x_test)
    
    #绘图  
    plt.title(u'LinearRegression Diabetes')            #标题  
    plt.xlabel(u'Attributes')                          #x轴坐标  
    plt.ylabel(u'Measure of disease')                  #y轴坐标    
    plt.scatter(diabetes_x_test, diabetes_y_test, color = 'black')  #散点图   
    plt.plot(diabetes_x_test, pre, color='blue', linewidth = 2)     #预测直线
    plt.show()          
    

    输出结果如图5所示,每个点表示真实的值,而直线表示预测的结果。

    在这里插入图片描述


    (3).代码优化
    下面代码增加了几个优化措施,包括增加了斜率、 截距的计算,可视化绘图增加了散点到线性方程的距离线,增加了保存图片设置像素代码等。这些优化都更好地帮助我们分析真实的数据集。

    # -*- coding: utf-8 -*-
    # By:Eastmount CSDN 2021-07-03
    from sklearn import datasets
    import numpy as np
    from sklearn import linear_model
    import matplotlib.pyplot as plt
    
    #第一步 数据集划分
    d = datasets.load_diabetes()  #数据 10*442
    x = d.data
    x_one = x[:,np.newaxis, 2]    #获取一个特征 第3列数据
    y = d.target                  #获取的正确结果
    x_train = x_one[:-42]         #训练集X [  0:400]
    x_test = x_one[-42:]          #预测集X [401:442]
    y_train = y[:-42]             #训练集Y [  0:400]
    y_test = y[-42:]              #预测集Y [401:442]
    
    #第二步 线性回归实现
    clf = linear_model.LinearRegression()
    print(clf)
    clf.fit(x_train, y_train)
    pre = clf.predict(x_test)
    print('预测结果', pre)
    print('真实结果', y_test)
       
    #第三步 评价结果
    cost = np.mean(y_test-pre)**2   #2次方
    print('平方和计算:', cost)
    print('系数', clf.coef_) 
    print('截距', clf.intercept_)  
    print('方差', clf.score(x_test, y_test))
    
    #第四步 绘图
    plt.plot(x_test, y_test, 'k.')      #散点图
    plt.plot(x_test, pre, 'g-')        #预测回归直线
    #绘制点到直线距离
    for idx, m in enumerate(x_test):
        plt.plot([m, m],[y_test[idx], pre[idx]], 'r-')
    
    plt.savefig('blog12-01.png', dpi=300) #保存图片
    plt.show()      
    

    绘制的图形如图6所示。

    在这里插入图片描述

    输出结果如下:

    LinearRegression(copy_X=True, fit_intercept=True, n_jobs=1, normalize=False)
    预测结果 [ 196.51241167  109.98667708  121.31742804  245.95568858  204.75295782
      270.67732703   75.99442421  241.8354155   104.83633574  141.91879342
      126.46776938  208.8732309   234.62493762  152.21947611  159.42995399
      161.49009053  229.47459628  221.23405012  129.55797419  100.71606266
      118.22722323  168.70056841  227.41445974  115.13701842  163.55022706
      114.10695016  120.28735977  158.39988572  237.71514243  121.31742804
       98.65592612  123.37756458  205.78302609   95.56572131  154.27961264
      130.58804246   82.17483382  171.79077322  137.79852034  137.79852034
      190.33200206   83.20490209]
    真实结果 [ 175.   93.  168.  275.  293.  281.   72.  140.  189.  181.  209.  136.
      261.  113.  131.  174.  257.   55.   84.   42.  146.  212.  233.   91.
      111.  152.  120.   67.  310.   94.  183.   66.  173.   72.   49.   64.
       48.  178.  104.  132.  220.   57.]
    
    平方和计算: 83.192340827
    系数 [ 955.70303385]
    截距 153.000183957
    方差 0.427204267067
    

    其中cost = np.mean(y_test-pre)**2表示计算预测结果和真实结果之间的平方和,为83.192340827,根据系数和截距得出其方程为:y = 955.70303385 * x + 153.000183957。


    三.多项式回归分析

    1.基础概念

    线性回归研究的是一个目标变量和一个自变量之间的回归问题,但有时候在很多实际问题中,影响目标变量的自变量往往不止一个,而是多个,比如绵羊的产毛量这一变量同时受到绵羊体重、胸围、体长等多个变量的影响,因此需要设计一个目标变量与多个自变量间的回归分析,即多元回归分析。由于线性回归并不适用于所有的数据,我们需要建立曲线来适应我们的数据,现实世界中的曲线关系很多都是增加多项式实现的,比如一个二次函数模型:

    在这里插入图片描述

    再或者一个三次函数模型:

    在这里插入图片描述

    这两个模型我们绘制的图形如下所示:

    在这里插入图片描述

    多项式回归(Polynomial Regression)是研究一个因变量与一个或多个自变量间多项式的回归分析方法。如果自变量只有一个时,称为一元多项式回归;如果自变量有多个时,称为多元多项式回归。在一元回归分析中,如果依变量y与自变量x的关系为非线性的,但是又找不到适当的函数曲线来拟合,则可以采用一元多项式回归。17.3小节主要讲解一元多次的多项式回归分析,一元m次多项式方程如下:

    在这里插入图片描述

    其方程的求解过程希望读者下来自行学习,接下来作者主要讲解Python如何代码实现多项式回归分析的。


    2.PolynomialFeatures

    Python的多项式回归需要导入sklearn.preprocessing子类中PolynomialFeatures类实现。PolynomialFeatures对应的函数原型如下:

    class sklearn.preprocessing.PolynomialFeatures(degree=2, 
    		interaction_only=False, 
    		include_bias=True)
    

    PolynomialFeatures类在Sklearn官网给出的解释是:专门产生多项式的模型或类,并且多项式包含的是相互影响的特征集。共有三个参数,degree表示多项式阶数,一般默认值是2;interaction_only如果值是true(默认是False),则会产生相互影响的特征集;include_bias表示是否包含偏差列。

    PolynomialFeatures类通过实例化一个多项式,建立等差数列矩阵,然后进行训练和预测,最后绘制相关图形,接下来与前面的一元线性回归分析进行对比试验。


    3.多项式回归预测成本和利润

    本小节主要讲解多项式回归分析实例,分析的数据集是表17.1提供的企业成本和利润数据集。下面直接给出线性回归和多项式回归分析对比的完整代码和详细注释。

    # -*- coding: utf-8 -*-
    # By:Eastmount CSDN 2021-07-03
    from sklearn.linear_model import LinearRegression     
    from sklearn.preprocessing import PolynomialFeatures
    import matplotlib.pyplot as plt       
    import numpy as np
    
    #X表示企业成本 Y表示企业利润
    X = [[400], [450], [486], [500], [510], [525], [540], [549], [558], [590], [610], [640], [680], [750], [900]]
    Y = [[80], [89], [92], [102], [121], [160], [180], [189], [199], [203], [247], [250], [259], [289], [356]]
    print('数据集X: ', X)
    print('数据集Y: ', Y)
    
    #第一步 线性回归分析
    clf = LinearRegression() 
    clf.fit(X, Y)                     
    X2 = [[400], [750], [950]]
    Y2 = clf.predict(X2)
    print(Y2)
    res = clf.predict(np.array([1200]).reshape(-1, 1))[0]   
    print('预测成本1200元的利润:$%.1f' % res) 
    plt.plot(X, Y, 'ks')    #绘制训练数据集散点图
    plt.plot(X2, Y2, 'g-')  #绘制预测数据集直线
    
    #第二步 多项式回归分析
    xx = np.linspace(350,950,100) #350到950等差数列
    quadratic_featurizer = PolynomialFeatures(degree = 2) #实例化一个二次多项式
    x_train_quadratic = quadratic_featurizer.fit_transform(X) #用二次多项式x做变换
    X_test_quadratic = quadratic_featurizer.transform(X2)
    regressor_quadratic = LinearRegression()
    regressor_quadratic.fit(x_train_quadratic, Y)
    
    #把训练好X值的多项式特征实例应用到一系列点上,形成矩阵
    xx_quadratic = quadratic_featurizer.transform(xx.reshape(xx.shape[0], 1))
    plt.plot(xx, regressor_quadratic.predict(xx_quadratic), "r--",
             label="$y = ax^2 + bx + c$",linewidth=2)
    plt.legend()
    plt.show()    
    

    输出图形如下图所示,其中黑色散点图表示真实的企业成本和利润的关系,绿色直线为一元线性回归方程,红色虚曲线为二次多项式方程。它更接近真实的散点图。

    在这里插入图片描述

    这里我们使用R方(R-Squared)来评估多项式回归预测的效果,R方也叫确定系数(Coefficient of Determination),它表示模型对现实数据拟合的程度。计算R方的方法有几种,一元线性回归中R方等于皮尔逊积矩相关系数(Pearson Product Moment Correlation Coefficient)的平方,该方法计算的R方是一定介于0~1之间的正数。另一种是Sklearn库提供的方法来计算R方。R方计算代码如下:

    print('1 r-squared', clf.score(X, Y))
    print('2 r-squared', regressor_quadratic.score(x_train_quadratic, Y))
    

    输出如下所示:

    ('1 r-squared', 0.9118311887769025)
    ('2 r-squared', 0.94073599498559335)
    

    在这里插入图片描述

    一元线性回归的R方值为0.9118,多项式回归的R方值为0.9407,说明数据集中超过94%的价格都可以通过模型解释。最后补充5次项的拟合过程,下面只给出核心代码。

    # -*- coding: utf-8 -*-
    # By:Eastmount CSDN 2021-07-03
    from sklearn.linear_model import LinearRegression     
    from sklearn.preprocessing import PolynomialFeatures
    import matplotlib.pyplot as plt       
    import numpy as np
    
    #X表示企业成本 Y表示企业利润
    X = [[400], [450], [486], [500], [510], [525], [540], [549], [558], [590], [610], [640], [680], [750], [900]]
    Y = [[80], [89], [92], [102], [121], [160], [180], [189], [199], [203], [247], [250], [259], [289], [356]]
    print('数据集X: ', X)
    print('数据集Y: ', Y)
    
    #第一步 线性回归分析
    clf = LinearRegression() 
    clf.fit(X, Y)                     
    X2 = [[400], [750], [950]]
    Y2 = clf.predict(X2)
    print(Y2)
    res = clf.predict(np.array([1200]).reshape(-1, 1))[0]   
    print('预测成本1200元的利润:$%.1f' % res) 
    plt.plot(X, Y, 'ks')    #绘制训练数据集散点图
    plt.plot(X2, Y2, 'g-')  #绘制预测数据集直线
    
    #第二步 多项式回归分析
    xx = np.linspace(350,950,100) 
    quadratic_featurizer = PolynomialFeatures(degree = 5) 
    x_train_quadratic = quadratic_featurizer.fit_transform(X) 
    X_test_quadratic = quadratic_featurizer.transform(X2)
    regressor_quadratic = LinearRegression()
    regressor_quadratic.fit(x_train_quadratic, Y)
    #把训练好X值的多项式特征实例应用到一系列点上,形成矩阵
    xx_quadratic = quadratic_featurizer.transform(xx.reshape(xx.shape[0], 1))
    plt.plot(xx, regressor_quadratic.predict(xx_quadratic), "r--",
             label="$y = ax^2 + bx + c$",linewidth=2)
    plt.legend()
    plt.show()
    print('1 r-squared', clf.score(X, Y))
    print('5 r-squared', regressor_quadratic.score(x_train_quadratic, Y))
    
    # ('1 r-squared', 0.9118311887769025)
    # ('5 r-squared', 0.98087802460869788)
    

    输出如下所示,其中红色虚线为五次多项式曲线,它更加接近真实数据集的分布情况,而绿色直线为一元线性回归方程,显然相较于五次多项式曲线,线性方程拟合的结果更差。同时,五次多项式曲线的R方值为98.08%,非常准确的预测了数据趋势。

    在这里插入图片描述

    最后补充一点,建议多项式回归的阶数不要太高,否则会出现过拟合现象。


    四.逻辑回归

    1.基础原理

    在前面讲述的回归模型中,处理的因变量都是数值型区间变量,建立的模型描述是因变量的期望与自变量之间的线性关系或多项式曲线关系。比如常见的线性回归模型:

    在这里插入图片描述

    而在采用回归模型分析实际问题中,所研究的变量往往不全是区间变量而是顺序变量或属性变量,比如二项分布问题。通过分析年龄、性别、体质指数、平均血压、疾病指数等指标,判断一个人是否换糖尿病,Y=0表示未患病,Y=1表示患病,这里的响应变量是一个两点(0或1)分布变量,它就不能用h函数连续的值来预测因变量Y(Y只能取0或1)。

    总之,线性回归或多项式回归模型通常是处理因变量为连续变量的问题,如果因变量是定性变量,线性回归模型就不再适用了,此时需采用逻辑回归模型解决。

    逻辑回归(Logistic Regression)是用于处理因变量为分类变量的回归问题,常见的是二分类或二项分布问题,也可以处理多分类问题,它实际上是属于一种分类方法。

    在这里插入图片描述

    二分类问题的概率与自变量之间的关系图形往往是一个S型曲线,如图17.10所示,采用的Sigmoid函数实现。这里我们将该函数定义如下:

    在这里插入图片描述

    函数的定义域为全体实数,值域在[0,1]之间,x轴在0点对应的结果为0.5。当x取值足够大的时候,可以看成0或1两类问题,大于0.5可以认为是1类问题,反之是0类问题,而刚好是0.5,则可以划分至0类或1类。对于0-1型变量,y=1的概率分布公式定义如下:

    在这里插入图片描述

    y=0的概率分布公式定义如下:

    在这里插入图片描述

    其离散型随机变量期望值公式如下:

    在这里插入图片描述

    采用线性模型进行分析,其公式变换如下:

    在这里插入图片描述

    而实际应用中,概率p与因变量往往是非线性的,为了解决该类问题,我们引入了logit变换,使得logit§与自变量之间存在线性相关的关系,逻辑回归模型定义如下:

    在这里插入图片描述

    通过推导,概率p变换如下,这与Sigmoid函数相符,也体现了概率p与因变量之间的非线性关系。以0.5为界限,预测p大于0.5时,我们判断此时y更可能为1,否则y为0。

    在这里插入图片描述

    得到所需的Sigmoid函数后,接下来只需要和前面的线性回归一样,拟合出该式中n个参数θ即可。下列为绘制Sigmoid曲线,输出如图10所示。

    # -*- coding: utf-8 -*-
    # By:Eastmount CSDN 2021-07-03
    import matplotlib.pyplot as plt
    import numpy as np
    
    def Sigmoid(x):
        return 1.0 / (1.0 + np.exp(-x))
    
    x= np.arange(-10, 10, 0.1)
    h = Sigmoid(x)                #Sigmoid函数
    plt.plot(x, h)
    plt.axvline(0.0, color='k')   #坐标轴上加一条竖直的线(0位置)
    plt.axhspan(0.0, 1.0, facecolor='1.0', alpha=1.0, ls='dotted')  
    plt.axhline(y=0.5, ls='dotted', color='k') 
    plt.yticks([0.0, 0.5, 1.0])  #y轴标度
    plt.ylim(-0.1, 1.1)          #y轴范围
    plt.show()
    

    由于篇幅有限,逻辑回归构造损失函数J函数,求解最小J函数及回归参数θ的方法就不在叙述,原理和前面介绍的一样,请读者下去深入研究。

    在这里插入图片描述


    2.LogisticRegression

    LogisticRegression回归模型在Sklearn.linear_model子类下,调用sklearn逻辑回归算法步骤比较简单,即:

    • 导入模型。调用逻辑回归LogisticRegression()函数。
    • fit()训练。调用fit(x,y)的方法来训练模型,其中x为数据的属性,y为所属类型。
    • predict()预测。利用训练得到的模型对数据集进行预测,返回预测结果。

    代码如下:

    # -*- coding: utf-8 -*-
    # By:Eastmount CSDN 2021-07-03
    from sklearn.linear_model import LogisticRegression  #导入逻辑回归模型 
    clf = LogisticRegression()
    print(clf)
    clf.fit(train_feature,label)
    predict['label'] = clf.predict(predict_feature)
    

    输出函数的构造方法如下:

    LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,
              intercept_scaling=1, max_iter=100, multi_class='ovr', n_jobs=1,
              penalty='l2', random_state=None, solver='liblinear', tol=0.0001,
              verbose=0, warm_start=False)
    

    这里仅介绍两个参数:参数penalty表示惩罚项,包括两个可选值L1和L2。L1表示向量中各元素绝对值的和,常用于特征选择;L2表示向量中各个元素平方之和再开根号,当需要选择较多的特征时,使用L2参数,使他们都趋近于0。C值的目标函数约束条件为:s.t.||w||1<C,默认值是0,C值越小,则正则化强度越大。


    3.鸢尾花数据集回归分析实例

    下面将结合Scikit-learn官网的逻辑回归模型分析鸢尾花数据集。由于该数据分类标签划分为3类(0类、1类、2类),属于三分类问题,所以能利用逻辑回归模型对其进行分析。

    (1).鸢尾花数据集
    在Sklearn机器学习包中,集成了各种各样的数据集,包括前面的糖尿病数据集,这里引入的是鸢尾花卉(Iris)数据集,它也是一个很常用的数据集。该数据集一共包含4个特征变量,1个类别变量,共有150个样本。其中四个特征分别是萼片的长度和宽度、花瓣的长度和宽度,一个类别变量是标记鸢尾花所属的分类情况,该值包含三种情况,即山鸢尾(Iris-setosa)、变色鸢尾(Iris-versicolor)和维吉尼亚鸢尾(Iris-virginica)。鸢尾花数据集详细介绍如表2所示:

    在这里插入图片描述

    Class 类别变量。0表示山鸢尾,1表示变色鸢尾,2表示维吉尼亚鸢尾。 int
    iris里有两个属性iris.data,iris.target。data是一个矩阵,每一列代表了萼片或花瓣的长宽,一共4列,每一行代表一个被测量的鸢尾植物,一共采样了150条记录,即150朵鸢尾花样本。

    from sklearn.datasets import load_iris   #导入数据集iris
    iris = load_iris()  #载入数据集
    print(iris.data)
    

    输出如下所示:

    [[ 5.1  3.5  1.4  0.2]
     [ 4.9  3.   1.4  0.2]
     [ 4.7  3.2  1.3  0.2]
     [ 4.6  3.1  1.5  0.2]
     ....
     [ 6.7  3.   5.2  2.3]
     [ 6.3  2.5  5.   1.9]
     [ 6.5  3.   5.2  2. ]
     [ 6.2  3.4  5.4  2.3]
     [ 5.9  3.   5.1  1.8]]
    

    target是一个数组,存储了每行数据对应的样本属于哪一类鸢尾植物,要么是山鸢尾(值为0),要么是变色鸢尾(值为1),要么是维吉尼亚鸢尾(值为2),数组的长度是150。

    print(iris.target)           #输出真实标签
    print(len(iris.target))      #150个样本 每个样本4个特征
    print(iris.data.shape)  
    
    [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
     1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2
     2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
     2 2]
    150
    (150L, 4L)
    

    从输出结果可以看到,类标共分为三类,前面50个类标位0,中间50个类标位1,后面为2。下面给详细介绍使用逻辑回归对这个数据集进行分析的代码。


    (2).散点图绘制
    在载入了鸢尾花数据集(数据data和标签target)之后,我们需要获取其中两列数据或两个特征,再调用scatter()函数绘制散点图。其中获取一个特征的核心代码为:X = [x[0] for x in DD],将获取的值赋值给X变量。完整代码如下:

    # -*- coding: utf-8 -*-
    # By:Eastmount CSDN 2021-07-03
    import matplotlib.pyplot as plt
    import numpy as np
    from sklearn.datasets import load_iris    #导入数据集iris
      
    #载入数据集  
    iris = load_iris()  
    print(iris.data)           #输出数据集  
    print(iris.target)         #输出真实标签
    
    #获取花卉两列数据集  
    DD = iris.data  
    X = [x[0] for x in DD]  
    print(X)  
    Y = [x[1] for x in DD]  
    print(Y)  
      
    #plt.scatter(X, Y, c=iris.target, marker='x')
    plt.scatter(X[:50], Y[:50], color='red', marker='o', label='setosa') #前50个样本
    plt.scatter(X[50:100], Y[50:100], color='blue', marker='x', label='versicolor') #中间50个
    plt.scatter(X[100:], Y[100:],color='green', marker='+', label='Virginica') #后50个样本
    plt.legend(loc=2) #左上角
    plt.show()
    

    输出如图11所示:

    在这里插入图片描述


    (3).线性回归分析
    下述代码先获取鸢尾花数据集的前两列数据,再调用Sklearn库中线性回归模型进行分析,完整代码如文件所示。

    # -*- coding: utf-8 -*-
    # By:Eastmount CSDN 2021-07-03
    
    #第一步 导入数据集
    from sklearn.datasets import load_iris
    hua = load_iris()
    
    #获取花瓣的长和宽
    x = [n[0] for n in hua.data]
    y = [n[1] for n in hua.data]
    import numpy as np #转换成数组
    x = np.array(x).reshape(len(x),1)
    y = np.array(y).reshape(len(y),1)
    
    #第二步 线性回归分析
    from sklearn.linear_model import LinearRegression
    clf = LinearRegression()
    clf.fit(x,y)
    pre = clf.predict(x)
    print(pre)
    
    #第三步 画图
    import matplotlib.pyplot as plt
    plt.scatter(x,y,s=100)
    plt.plot(x,pre,"r-",linewidth=4)
    for idx, m in enumerate(x):
        plt.plot([m,m],[y[idx],pre[idx]], 'g-')
    plt.show()
    

    输出图形如图12所示,并且可以看到所有散点到拟合的一元一次方程的距离。

    在这里插入图片描述


    (4).逻辑回归分析鸢尾花
    讲解完线性回归分析之后,那如果用逻辑回归分析的结果究竟如何呢?下面开始讲述。从散点图(图11)中可以看出,数据集是线性可分的,划分为3类,分别对应三种类型的鸢尾花,下面采用逻辑回归对其进行分析预测。

    前面使用X=[x[0] for x in DD]获取第一列数据,Y=[x[1] for x in DD]获取第二列数据,这里采用另一种方法,iris.data[:, :2]获取其中两列数据或两个特征,完整代码如下:

    # -*- coding: utf-8 -*-
    # By:Eastmount CSDN 2021-07-03
    import matplotlib.pyplot as plt
    import numpy as np
    from sklearn.datasets import load_iris   
    from sklearn.linear_model import LogisticRegression 
    
    #载入数据集
    iris = load_iris()         
    X = X = iris.data[:, :2]   #获取花卉两列数据集
    Y = iris.target           
    
    #逻辑回归模型
    lr = LogisticRegression(C=1e5)  
    lr.fit(X,Y)
    
    #meshgrid函数生成两个网格矩阵
    h = .02
    x_min, x_max = X[:, 0].min() - .5, X[:, 0].max() + .5
    y_min, y_max = X[:, 1].min() - .5, X[:, 1].max() + .5
    xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
    
    #pcolormesh函数将xx,yy两个网格矩阵和对应的预测结果Z绘制在图片上
    Z = lr.predict(np.c_[xx.ravel(), yy.ravel()])
    Z = Z.reshape(xx.shape)
    plt.figure(1, figsize=(8,6))
    plt.pcolormesh(xx, yy, Z, cmap=plt.cm.Paired)
    
    #绘制散点图
    plt.scatter(X[:50,0], X[:50,1], color='red',marker='o', label='setosa')
    plt.scatter(X[50:100,0], X[50:100,1], color='blue', marker='x', label='versicolor')
    plt.scatter(X[100:,0], X[100:,1], color='green', marker='s', label='Virginica') 
    
    plt.xlabel('Sepal length')
    plt.ylabel('Sepal width')
    plt.xlim(xx.min(), xx.max())
    plt.ylim(yy.min(), yy.max())
    plt.xticks(())
    plt.yticks(())
    plt.legend(loc=2) 
    plt.show()
    

    输出如图13所示。经过逻辑回归后划分为三个区域,左上角部分为红色的圆点,对应setosa鸢尾花;右上角部分为绿色方块,对应virginica鸢尾花;中间下部分为蓝色星形,对应versicolor鸢尾花。散点图为各数据点真实的花类型,划分的三个区域为数据点预测的花类型,预测的分类结果与训练数据的真实结果结果基本一致,部分鸢尾花出现交叉。

    在这里插入图片描述

    下面作者对导入数据集后的代码进行详细讲解。

    • lr = LogisticRegression(C=1e5)
      初始化逻辑回归模型,C=1e5表示目标函数。
    • lr.fit(X,Y)
      调用逻辑回归模型进行训练,参数X为数据特征,参数Y为数据类标。
    • x_min, x_max = X[:, 0].min() - .5, X[:, 0].max() + .5
    • y_min, y_max = X[:, 1].min() - .5, X[:, 1].max() + .5
    • xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
      获取鸢尾花数据集的两列数据,对应为花萼长度和花萼宽度,每个点的坐标就是(x,y)。 先取X二维数组的第一列(长度)的最小值、最大值和步长h(设置为0.02)生成数组,再取X二维数组的第二列(宽度)的最小值、最大值和步长h生成数组, 最后用meshgrid函数生成两个网格矩阵xx和yy,如下所示:
    [[ 3.8   3.82  3.84 ...,  8.36  8.38  8.4 ]
     [ 3.8   3.82  3.84 ...,  8.36  8.38  8.4 ]
     ..., 
     [ 3.8   3.82  3.84 ...,  8.36  8.38  8.4 ]
     [ 3.8   3.82  3.84 ...,  8.36  8.38  8.4 ]]
    [[ 1.5   1.5   1.5  ...,  1.5   1.5   1.5 ]
     [ 1.52  1.52  1.52 ...,  1.52  1.52  1.52]
     ..., 
     [ 4.88  4.88  4.88 ...,  4.88  4.88  4.88]
     [ 4.9   4.9   4.9  ...,  4.9   4.9   4.9 ]]
    
    • Z = lr.predict(np.c_[xx.ravel(), yy.ravel()])
      调用ravel()函数将xx和yy的两个矩阵转变成一维数组,由于两个矩阵大小相等,因此两个一维数组大小也相等。np.c_[xx.ravel(), yy.ravel()]是获取并合并成矩阵,即:
    xx.ravel() 
    [ 3.8   3.82  3.84 ...,  8.36  8.38  8.4 ]
    yy.ravel() 
    [ 1.5  1.5  1.5 ...,  4.9  4.9  4.9]
    np.c_[xx.ravel(), yy.ravel()]
    [[ 3.8   1.5 ]
     [ 3.82  1.5 ]
     [ 3.84  1.5 ]
     ..., 
     [ 8.36  4.9 ]
     [ 8.38  4.9 ]
     [ 8.4   4.9 ]]
    

    总之,上述操作是把第一列花萼长度数据按h取等分作为行,并复制多行得到xx网格矩阵;再把第二列花萼宽度数据按h取等分作为列,并复制多列得到yy网格矩阵;最后将xx和yy矩阵都变成两个一维数组,再调用np.c_[]函数将其组合成一个二维数组进行预测。

    • Z = logreg.predict(np.c_[xx.ravel(), yy.ravel()])
      调用predict()函数进行预测,预测结果赋值给Z。即:
    Z = logreg.predict(np.c_[xx.ravel(), yy.ravel()])
    [1 1 1 ..., 2 2 2]
    size: 39501
    
    • Z = Z.reshape(xx.shape)
      调用reshape()函数修改形状,将Z变量转换为两个特征(长度和宽度),则39501个数据转换为171*231的矩阵。Z = Z.reshape(xx.shape)输出如下:
    [[1 1 1 ..., 2 2 2]
     [1 1 1 ..., 2 2 2]
     [0 1 1 ..., 2 2 2]
     ..., 
     [0 0 0 ..., 2 2 2]
     [0 0 0 ..., 2 2 2]
     [0 0 0 ..., 2 2 2]]
    
    • plt.pcolormesh(xx, yy, Z, cmap=plt.cm.Paired)
      调用pcolormesh()函数将xx、yy两个网格矩阵和对应的预测结果Z绘制在图片上,可以发现输出为三个颜色区块,分布表示分类的三类区域。cmap=plt.cm.Paired表示绘图样式选择Paired主题,输出区域如下图所示:

    在这里插入图片描述

    • plt.scatter(X[:50,0], X[:50,1], color=‘red’,marker=‘o’, label=‘setosa’)
      调用scatter()绘制散点图,第一个参数为第一列数据(长度),第二个参数为第二列数据(宽度),第三、四个参数为设置点的颜色为红色,款式为圆圈,最后标记为setosa。

    五.本章小结

    回归分析是通过建立一个回归方程用来预测目标值,并求解这个回归方程的回归系数的方法。它是统计学中最重要的工具之一,包括线性回归、多项式回归、逻辑回归、非线性回归等。常用来确定变量之间是否存在相关关系,并找出数学表达式,也可以通过控制几个变量的值来预测另一个变量的值,比如房价预测、增长趋势、是否患病等问题。

    在Python中,我们通过调用Sklearn机器学习库的LinearRegression模型实现线性回归分析,调用PolynomialFeatures模型实现多项式回归分析,调用LogisticRegression模型实现逻辑回归分析。希望读者实现本章节中的每一部分代码,从而更好的用于自己的研究领域、解决自己遇到的问题。

    该系列所有代码下载地址:

    感谢在求学路上的同行者,不负遇见,勿忘初心。这周的留言感慨~

    在这里插入图片描述

    (By:娜璋之家 Eastmount 2021-07-03 夜于武汉 https://blog.csdn.net/Eastmount )


    参考文献:

    • [1] 杨秀璋. 专栏:知识图谱、web数据挖掘及NLP - CSDN博客[EB/OL]. (2016-09-19)[2017-11-07]. http://blog.csdn.net/column/details/eastmount-kgdmnlp.html.
    • [2] 张良均,王路,谭立云,苏剑林. Python数据分析与挖掘实战[M]. 北京:机械工业出版社,2016.
    • [3] (美)Wes McKinney著. 唐学韬等译. 利用Python进行数据分析[M]. 北京:机械工业出版社,2013.
    • [4] Jiawei Han,Micheline Kamber著. 范明,孟小峰译. 数据挖掘概念与技术. 北京:机械工业出版社,2007.
    • [5] 杨秀璋. [Python数据挖掘课] 五.线性回归知识及预测糖尿病实例[EB/OL].(2016-10-28)[2017-11-07]. http://blog.csdn.net/eastmount/article/details/52929765.
    • [6] 杨秀璋. [Python数据挖掘课程] 九.回归模型LinearRegression简单分析氧化物数据[EB/OL]. (2017-03-05)[2017-11-07].http://blog.csdn.net/eastmount/article/
      details/60468818.
    • [7] scikit-learn. sklearn.linear_model.LogisticRegression[EB/OL]. (2017)[2017-11-17]. http://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LogisticRegression.html.
    • [8] scikit-learn. Logistic Regression 3-class Classifier[EB/OL]. (2017)[2017-11-17]. http://scikit-learn.org/stable/auto_examples/linear_model/plot_iris_logistic.html#sphx-glr-auto-examples-linear-model-plot-iris-logistic-py.
    • [9] 吴恩达. Coursera公开课: 斯坦福大学机器学习"[EB/OL]. (2011-2017)[2017-11-15]. http://open.163.com/special/opencourse/machinelearning.html.
    • [10] scikit-learn. Sklearn Datasets[EB/OL]. (2017)[2017-11-15]. http://scikit-learn.org/
      stable/datasets/.
    • [11] lsldd. 用Python开始机器学习(7:逻辑回归分类)[EB/OL]. (2014-11-27)[2017-11-15]. http://blog.csdn.net/lsldd/article/details/41551797.
    • [12] 杨秀璋. [python数据挖掘课程] 十六.逻辑回归LogisticRegression分析鸢尾花数据[EB/OL]. (2017-09-10)[2017-11-15]. http://blog.csdn.net/eastmount/article/details/77920470.
    • [13] 杨秀璋. [python数据挖掘课程] 十八.线性回归及多项式回归分析四个案例分享[EB/OL]. (2017-11-26)[2017-11-26]. http://blog.csdn.net/eastmount/article/details/78635096.
    展开全文
  • 机器学习系列(3)_逻辑回归应用之Kaggle泰坦尼克之灾

    万次阅读 多人点赞 2015-11-12 12:07:12
    手把手机器学习逻辑回归应用——Kaggle泰坦尼克之灾1.引言先说一句,年末双十一什么的一来,真是非(mang)常(cheng)欢(gou)乐(le)!然后push自己抽出时间来写这篇blog的原因也非常简单: 写完前两篇逻辑回归的介绍...

    作者: 寒小阳
    时间:2015年11月。
    出处:http://blog.csdn.net/han_xiaoyang/article/details/49797143
    声明:版权所有,转载请注明出处,谢谢。

    1.引言

    先说一句,年末双十一什么的一来,真是非(mang)常(cheng)欢(gou)乐(le)!然后push自己抽出时间来写这篇blog的原因也非常简单:

    • 写完前两篇逻辑回归的介绍和各个角度理解之后,我们讨论群(戳我入群)的小伙伴们纷纷表示『好像很高级的样纸,but 然并卵 啊!你们倒是拿点实际数据来给我们看看,这玩意儿 有!什!么!用!啊!』
    • talk is cheap, show me the code!
    • no example say a jb!

    OK,OK,这就来了咯,同学们别着急,我们先找个简单的实际例子,来看看,所谓的数据挖掘或者机器学习实际应用到底是怎么样一个过程。

    『喂,那几个说要看大数据上机器学习应用的,对,就是说你们!别着急好么,我们之后拉点大一点实际数据用liblinear或者spark,MLlib跑给你们看,行不行?咱们先拿个实例入入门嘛』

    好了,我是一个严肃的技术研究和分享者,咳咳,不能废话了,各位同学继续往下看吧!

    2.背景

    2.1 关于Kaggle

    • 我是Kaggle地址,翻我牌子
    • 亲,逼格这么高的地方,你一定听过对不对?是!这就是那个无数『数据挖掘先驱』们,在回答"枪我有了,哪能找到靶子练练手啊?"时候的答案!
    • 这是一个要数据有数据,要实际应用场景有场景,要一起在数据挖掘领域high得不要不要的小伙伴就有小伙伴的地方啊!!!

    艾玛,逗逼模式开太猛了。恩,不闹,不闹,说正事,Kaggle是一个数据分析建模的应用竞赛平台,有点类似KDD-CUP(国际知识发现和数据挖掘竞赛),企业或者研究者可以将问题背景、数据、期望指标等发布到Kaggle上,以竞赛的形式向广大的数据科学家征集解决方案。而热爱数(dong)据(shou)挖(zhe)掘(teng)的小伙伴们可以下载/分析数据,使用统计/机器学习/数据挖掘等知识,建立算法模型,得出结果并提交,排名top的可能会有奖金哦!

    2.2 关于泰坦尼克号之灾

    • 带大家去该问题页面溜达一圈吧

      • 下面是问题背景页
        泰坦尼克号问题背景页
      • 下面是可下载Data的页面
        Data页面
      • 下面是小伙伴们最爱的forum页面,你会看到各种神级人物厉(qi)害(pa)的数据处理/建模想法,你会直视『世界真奇妙』。
        论坛页面
    • 泰坦尼克号问题之背景

      • 就是那个大家都熟悉的『Jack and Rose』的故事,豪华游艇倒了,大家都惊恐逃生,可是救生艇的数量有限,无法人人都有,副船长发话了『lady and kid first!』,所以是否获救其实并非随机,而是基于一些背景有rank先后的

      • 训练和测试数据是一些乘客的个人信息以及存活状况,要尝试根据它生成合适的模型并预测其他人的存活状况

      • 对,这是一个二分类问题,是我们之前讨论的logistic regression所能处理的范畴。

    3.说明

    接触过Kaggle的同学们可能知道这个问题,也可能知道RandomForest和SVM等等算法,甚至还对多个模型做过融合,取得过非常好的结果,那maybe这篇文章并不是针对你的,你可以自行略过。

    我们因为之前只介绍了Logistic Regression这一种分类算法。所以本次的问题解决过程和优化思路,都集中在这种算法上。其余的方法可能我们之后的文章里会提到。

    说点个人的观点。不一定正确。
    『解决一个问题的方法和思路不止一种』
    『没有所谓的机器学习算法优劣,也没有绝对高性能的机器学习算法,只有在特定的场景、数据和特征下更合适的机器学习算法。』

    4.怎么做?

    手把手教程马上就来,先来两条我看到的,觉得很重要的经验。

    1. 印象中Andrew Ng老师似乎在coursera上说过,应用机器学习,千万不要一上来就试图做到完美,先撸一个baseline的model出来,再进行后续的分析步骤,一步步提高,所谓后续步骤可能包括『分析model现在的状态(欠/过拟合),分析我们使用的feature的作用大小,进行feature selection,以及我们模型下的bad case和产生的原因』等等。

    2. Kaggle上的大神们,也分享过一些experience,说几条我记得的哈:

      • 『对数据的认识太重要了!』
      • 『数据中的特殊点/离群点的分析和处理太重要了!』
      • 『特征工程(feature engineering)太重要了!在很多Kaggle的场景下,甚至比model本身还要重要』
      • 『要做模型融合(model ensemble)啊啊啊!』

    更多的经验分享请加讨论群,具体方式请联系作者,或者参见《“ML学分计划”说明书》

    5.初探数据

    先看看我们的数据,长什么样吧。在Data下我们train.csv和test.csv两个文件,分别存着官方给的训练和测试数据。

    import pandas as pd #数据分析
    import numpy as np #科学计算
    from pandas import Series,DataFrame
    
    data_train = pd.read_csv("/Users/Hanxiaoyang/Titanic_data/Train.csv")
    data_train
    

    pandas是常用的python数据处理包,把csv文件读入成dataframe各式,我们在ipython notebook中,看到data_train如下所示:

    训练数据

    这就是典型的dataframe格式,如果你没接触过这种格式,完全没有关系,你就把它想象成Excel里面的列好了。
    我们看到,总共有12列,其中Survived字段表示的是该乘客是否获救,其余都是乘客的个人信息,包括:

    • PassengerId => 乘客ID
    • Pclass => 乘客等级(1/2/3等舱位)
    • Name => 乘客姓名
    • Sex => 性别
    • Age => 年龄
    • SibSp => 堂兄弟/妹个数
    • Parch => 父母与小孩个数
    • Ticket => 船票信息
    • Fare => 票价
    • Cabin => 客舱
    • Embarked => 登船港口

    逐条往下看,要看完这么多条,眼睛都有一种要瞎的赶脚。好吧,我们让dataframe自己告诉我们一些信息,如下所示:

    data_train.info()
    

    看到了如下的信息:
    数据信息

    上面的数据说啥了?它告诉我们,训练数据中总共有891名乘客,但是很不幸,我们有些属性的数据不全,比如说:

    • Age(年龄)属性只有714名乘客有记录
    • Cabin(客舱)更是只有204名乘客是已知的

    似乎信息略少啊,想再瞄一眼具体数据数值情况呢?恩,我们用下列的方法,得到数值型数据的一些分布(因为有些属性,比如姓名,是文本型;而另外一些属性,比如登船港口,是类目型。这些我们用下面的函数是看不到的):

    数值型数据基本信息

    我们从上面看到更进一步的什么信息呢?
    mean字段告诉我们,大概0.383838的人最后获救了,2/3等舱的人数比1等舱要多,平均乘客年龄大概是29.7岁(计算这个时候会略掉无记录的)等等…

    6.数据初步分析

    每个乘客都这么多属性,那我们咋知道哪些属性更有用,而又应该怎么用它们啊?说实话这会儿我也不知道,但我们记得前面提到过

    • 『对数据的认识太重要了!』
    • 『对数据的认识太重要了!』
    • 『对数据的认识太重要了!』

    重要的事情说三遍,恩,说完了。仅仅最上面的对数据了解,依旧无法给我们提供想法和思路。我们再深入一点来看看我们的数据,看看每个/多个 属性和最后的Survived之间有着什么样的关系呢。

    6.1 乘客各属性分布

    脑容量太有限了…数值看花眼了。我们还是统计统计,画些图来看看属性和结果之间的关系好了,代码如下:

    import matplotlib.pyplot as plt
    fig = plt.figure()
    fig.set(alpha=0.2)  # 设定图表颜色alpha参数
    
    plt.subplot2grid((2,3),(0,0))             # 在一张大图里分列几个小图
    data_train.Survived.value_counts().plot(kind='bar')# 柱状图 
    plt.title(u"获救情况 (1为获救)") # 标题
    plt.ylabel(u"人数")  
    
    plt.subplot2grid((2,3),(0,1))
    data_train.Pclass.value_counts().plot(kind="bar")
    plt.ylabel(u"人数")
    plt.title(u"乘客等级分布")
    
    plt.subplot2grid((2,3),(0,2))
    plt.scatter(data_train.Survived, data_train.Age)
    plt.ylabel(u"年龄")                         # 设定纵坐标名称
    plt.grid(b=True, which='major', axis='y') 
    plt.title(u"按年龄看获救分布 (1为获救)")
    
    
    plt.subplot2grid((2,3),(1,0), colspan=2)
    data_train.Age[data_train.Pclass == 1].plot(kind='kde')   
    data_train.Age[data_train.Pclass == 2].plot(kind='kde')
    data_train.Age[data_train.Pclass == 3].plot(kind='kde')
    plt.xlabel(u"年龄")# plots an axis lable
    plt.ylabel(u"密度") 
    plt.title(u"各等级的乘客年龄分布")
    plt.legend((u'头等舱', u'2等舱',u'3等舱'),loc='best') # sets our legend for our graph.
    
    
    plt.subplot2grid((2,3),(1,2))
    data_train.Embarked.value_counts().plot(kind='bar')
    plt.title(u"各登船口岸上船人数")
    plt.ylabel(u"人数")  
    plt.show()
    

    数据基本信息图示

    bingo,图还是比数字好看多了。所以我们在图上可以看出来,被救的人300多点,不到半数;3等舱乘客灰常多;遇难和获救的人年龄似乎跨度都很广;3个不同的舱年龄总体趋势似乎也一致,2/3等舱乘客20岁多点的人最多,1等舱40岁左右的最多(→_→似乎符合财富和年龄的分配哈,咳咳,别理我,我瞎扯的);登船港口人数按照S、C、Q递减,而且S远多于另外俩港口。

    这个时候我们可能会有一些想法了:

    • 不同舱位/乘客等级可能和财富/地位有关系,最后获救概率可能会不一样
    • 年龄对获救概率也一定是有影响的,毕竟前面说了,副船长还说『小孩和女士先走』呢
    • 和登船港口是不是有关系呢?也许登船港口不同,人的出身地位不同?

    口说无凭,空想无益。老老实实再来统计统计,看看这些属性值的统计分布吧。

    6.2 属性与获救结果的关联统计

    #看看各乘客等级的获救情况
    fig = plt.figure()
    fig.set(alpha=0.2)  # 设定图表颜色alpha参数
    
    Survived_0 = data_train.Pclass[data_train.Survived == 0].value_counts()
    Survived_1 = data_train.Pclass[data_train.Survived == 1].value_counts()
    df=pd.DataFrame({u'获救':Survived_1, u'未获救':Survived_0})
    df.plot(kind='bar', stacked=True)
    plt.title(u"各乘客等级的获救情况")
    plt.xlabel(u"乘客等级") 
    plt.ylabel(u"人数") 
    plt.show()
    

    各乘客等级的获救情况

    啧啧,果然,钱和地位对舱位有影响,进而对获救的可能性也有影响啊←_←
    咳咳,跑题了,我想说的是,明显等级为1的乘客,获救的概率高很多。恩,这个一定是影响最后获救结果的一个特征。

    #看看各性别的获救情况
    fig = plt.figure()
    fig.set(alpha=0.2)  # 设定图表颜色alpha参数
    
    Survived_m = data_train.Survived[data_train.Sex == 'male'].value_counts()
    Survived_f = data_train.Survived[data_train.Sex == 'female'].value_counts()
    df=pd.DataFrame({u'男性':Survived_m, u'女性':Survived_f})
    df.plot(kind='bar', stacked=True)
    plt.title(u"按性别看获救情况")
    plt.xlabel(u"性别") 
    plt.ylabel(u"人数")
    plt.show()
    

    各乘客等级的获救情况

    歪果盆友果然很尊重lady,lady first践行得不错。性别无疑也要作为重要特征加入最后的模型之中。

    再来个详细版的好了。

    
     #然后我们再来看看各种舱级别情况下各性别的获救情况
    fig=plt.figure()
    fig.set(alpha=0.65) # 设置图像透明度,无所谓
    plt.title(u"根据舱等级和性别的获救情况")
    
    ax1=fig.add_subplot(141)
    data_train.Survived[data_train.Sex == 'female'][data_train.Pclass != 3].value_counts().plot(kind='bar', label="female highclass", color='#FA2479')
    ax1.set_xticklabels([u"获救", u"未获救"], rotation=0)
    ax1.legend([u"女性/高级舱"], loc='best')
    
    ax2=fig.add_subplot(142, sharey=ax1)
    data_train.Survived[data_train.Sex == 'female'][data_train.Pclass == 3].value_counts().plot(kind='bar', label='female, low class', color='pink')
    ax2.set_xticklabels([u"未获救", u"获救"], rotation=0)
    plt.legend([u"女性/低级舱"], loc='best')
    
    ax3=fig.add_subplot(143, sharey=ax1)
    data_train.Survived[data_train.Sex == 'male'][data_train.Pclass != 3].value_counts().plot(kind='bar', label='male, high class',color='lightblue')
    ax3.set_xticklabels([u"未获救", u"获救"], rotation=0)
    plt.legend([u"男性/高级舱"], loc='best')
    
    ax4=fig.add_subplot(144, sharey=ax1)
    data_train.Survived[data_train.Sex == 'male'][data_train.Pclass == 3].value_counts().plot(kind='bar', label='male low class', color='steelblue')
    ax4.set_xticklabels([u"未获救", u"获救"], rotation=0)
    plt.legend([u"男性/低级舱"], loc='best')
    
    plt.show()
    
    

    各性别和舱位的获救情况

    恩,坚定了之前的判断。

    我们看看各登船港口的获救情况。

    fig = plt.figure()
    fig.set(alpha=0.2)  # 设定图表颜色alpha参数
    
    Survived_0 = data_train.Embarked[data_train.Survived == 0].value_counts()
    Survived_1 = data_train.Embarked[data_train.Survived == 1].value_counts()
    df=pd.DataFrame({u'获救':Survived_1, u'未获救':Survived_0})
    df.plot(kind='bar', stacked=True)
    plt.title(u"各登录港口乘客的获救情况")
    plt.xlabel(u"登录港口") 
    plt.ylabel(u"人数") 
    
    plt.show()
    

    各登船港口的获救情况

    下面我们来看看 堂兄弟/妹,孩子/父母有几人,对是否获救的影响。

    
    g = data_train.groupby(['SibSp','Survived'])
    df = pd.DataFrame(g.count()['PassengerId'])
    print df
    
    g = data_train.groupby(['SibSp','Survived'])
    df = pd.DataFrame(g.count()['PassengerId'])
    print df
    
    

    堂兄弟/妹影响

    父母/孩子影响

    好吧,没看出特别特别明显的规律(为自己的智商感到捉急…),先作为备选特征,放一放。

    
    #ticket是船票编号,应该是unique的,和最后的结果没有太大的关系,先不纳入考虑的特征范畴把
    #cabin只有204个乘客有值,我们先看看它的一个分布
    data_train.Cabin.value_counts()
    
    

    部分结果如下:
    Cabin分布

    这三三两两的…如此不集中…我们猜一下,也许,前面的ABCDE是指的甲板位置、然后编号是房间号?…好吧,我瞎说的,别当真…

    关键是Cabin这鬼属性,应该算作类目型的,本来缺失值就多,还如此不集中,注定是个棘手货…第一感觉,这玩意儿如果直接按照类目特征处理的话,太散了,估计每个因子化后的特征都拿不到什么权重。加上有那么多缺失值,要不我们先把Cabin缺失与否作为条件(虽然这部分信息缺失可能并非未登记,maybe只是丢失了而已,所以这样做未必妥当),先在有无Cabin信息这个粗粒度上看看Survived的情况好了。

    
    fig = plt.figure()
    fig.set(alpha=0.2)  # 设定图表颜色alpha参数
    
    Survived_cabin = data_train.Survived[pd.notnull(data_train.Cabin)].value_counts()
    Survived_nocabin = data_train.Survived[pd.isnull(data_train.Cabin)].value_counts()
    df=pd.DataFrame({u'有':Survived_cabin, u'无':Survived_nocabin}).transpose()
    df.plot(kind='bar', stacked=True)
    plt.title(u"按Cabin有无看获救情况")
    plt.xlabel(u"Cabin有无") 
    plt.ylabel(u"人数")
    plt.show()
    
    

    有无Cabin记录影响

    咳咳,有Cabin记录的似乎获救概率稍高一些,先这么着放一放吧。

    7.简单数据预处理

    大体数据的情况看了一遍,对感兴趣的属性也有个大概的了解了。
    下一步干啥?咱们该处理处理这些数据,为机器学习建模做点准备了。

    对了,我这里说的数据预处理,其实就包括了很多Kaggler津津乐道的feature engineering过程,灰常灰常有必要!

    『特征工程(feature engineering)太重要了!』
    『特征工程(feature engineering)太重要了!』
    『特征工程(feature engineering)太重要了!』

    恩,重要的事情说三遍。

    先从最突出的数据属性开始吧,对,Cabin和Age,有丢失数据实在是对下一步工作影响太大。

    先说Cabin,暂时我们就按照刚才说的,按Cabin有无数据,将这个属性处理成Yes和No两种类型吧。

    再说Age:

    通常遇到缺值的情况,我们会有几种常见的处理方式

    • 如果缺值的样本占总数比例极高,我们可能就直接舍弃了,作为特征加入的话,可能反倒带入noise,影响最后的结果了
    • 如果缺值的样本适中,而该属性非连续值特征属性(比如说类目属性),那就把NaN作为一个新类别,加到类别特征中
    • 如果缺值的样本适中,而该属性为连续值特征属性,有时候我们会考虑给定一个step(比如这里的age,我们可以考虑每隔2/3岁为一个步长),然后把它离散化,之后把NaN作为一个type加到属性类目中。
    • 有些情况下,缺失的值个数并不是特别多,那我们也可以试着根据已有的值,拟合一下数据,补充上。

    本例中,后两种处理方式应该都是可行的,我们先试试拟合补全吧(虽然说没有特别多的背景可供我们拟合,这不一定是一个多么好的选择)

    我们这里用scikit-learn中的RandomForest来拟合一下缺失的年龄数据(注:RandomForest是一个用在原始数据中做不同采样,建立多颗DecisionTree,再进行average等等来降低过拟合现象,提高结果的机器学习算法,我们之后会介绍到)

    
    from sklearn.ensemble import RandomForestRegressor
     
    ### 使用 RandomForestClassifier 填补缺失的年龄属性
    def set_missing_ages(df):
        
        # 把已有的数值型特征取出来丢进Random Forest Regressor中
        age_df = df[['Age','Fare', 'Parch', 'SibSp', 'Pclass']]
    
        # 乘客分成已知年龄和未知年龄两部分
        known_age = age_df[age_df.Age.notnull()].as_matrix()
        unknown_age = age_df[age_df.Age.isnull()].as_matrix()
    
        # y即目标年龄
        y = known_age[:, 0]
    
        # X即特征属性值
        X = known_age[:, 1:]
    
        # fit到RandomForestRegressor之中
        rfr = RandomForestRegressor(random_state=0, n_estimators=2000, n_jobs=-1)
        rfr.fit(X, y)
        
        # 用得到的模型进行未知年龄结果预测
        predictedAges = rfr.predict(unknown_age[:, 1::])
        
        # 用得到的预测结果填补原缺失数据
        df.loc[ (df.Age.isnull()), 'Age' ] = predictedAges 
        
        return df, rfr
    
    def set_Cabin_type(df):
        df.loc[ (df.Cabin.notnull()), 'Cabin' ] = "Yes"
        df.loc[ (df.Cabin.isnull()), 'Cabin' ] = "No"
        return df
    
    data_train, rfr = set_missing_ages(data_train)
    data_train = set_Cabin_type(data_train)
    
    

    处理Cabin和Age之后

    恩。目的达到,OK了。

    因为逻辑回归建模时,需要输入的特征都是数值型特征,我们通常会先对类目型的特征因子化。
    什么叫做因子化呢?举个例子:

    以Cabin为例,原本一个属性维度,因为其取值可以是[‘yes’,‘no’],而将其平展开为’Cabin_yes’,'Cabin_no’两个属性

    • 原本Cabin取值为yes的,在此处的"Cabin_yes"下取值为1,在"Cabin_no"下取值为0
    • 原本Cabin取值为no的,在此处的"Cabin_yes"下取值为0,在"Cabin_no"下取值为1

    我们使用pandas的"get_dummies"来完成这个工作,并拼接在原来的"data_train"之上,如下所示。

    
    dummies_Cabin = pd.get_dummies(data_train['Cabin'], prefix= 'Cabin')
    
    dummies_Embarked = pd.get_dummies(data_train['Embarked'], prefix= 'Embarked')
    
    dummies_Sex = pd.get_dummies(data_train['Sex'], prefix= 'Sex')
    
    dummies_Pclass = pd.get_dummies(data_train['Pclass'], prefix= 'Pclass')
    
    df = pd.concat([data_train, dummies_Cabin, dummies_Embarked, dummies_Sex, dummies_Pclass], axis=1)
    df.drop(['Pclass', 'Name', 'Sex', 'Ticket', 'Cabin', 'Embarked'], axis=1, inplace=True)
    df
    
    

    离散/因子化之后

    bingo,我们很成功地把这些类目属性全都转成0,1的数值属性了。

    这样,看起来,是不是我们需要的属性值都有了,且它们都是数值型属性呢。

    有一种临近结果的宠宠欲动感吧,莫急莫急,我们还得做一些处理,仔细看看Age和Fare两个属性,乘客的数值幅度变化,也忒大了吧!!如果大家了解逻辑回归与梯度下降的话,会知道,各属性值之间scale差距太大,将对收敛速度造成几万点伤害值!甚至不收敛! (╬▔皿▔)…所以我们先用scikit-learn里面的preprocessing模块对这俩货做一个scaling,所谓scaling,其实就是将一些变化幅度较大的特征化到[-1,1]之内。

    import sklearn.preprocessing as preprocessing
    scaler = preprocessing.StandardScaler()
    age_scale_param = scaler.fit(df['Age'])
    df['Age_scaled'] = scaler.fit_transform(df['Age'], age_scale_param)
    fare_scale_param = scaler.fit(df['Fare'])
    df['Fare_scaled'] = scaler.fit_transform(df['Fare'], fare_scale_param)
    df
    

    scaling

    恩,好看多了,万事俱备,只欠建模。马上就要看到成效了,哈哈。我们把需要的属性值抽出来,转成scikit-learn里面LogisticRegression可以处理的格式。

    8.逻辑回归建模

    我们把需要的feature字段取出来,转成numpy格式,使用scikit-learn中的LogisticRegression建模。

    from sklearn import linear_model
    
    # 用正则取出我们要的属性值
    train_df = df.filter(regex='Survived|Age_.*|SibSp|Parch|Fare_.*|Cabin_.*|Embarked_.*|Sex_.*|Pclass_.*')
    train_np = train_df.as_matrix()
    
    # y即Survival结果
    y = train_np[:, 0]
    
    # X即特征属性值
    X = train_np[:, 1:]
    
    # fit到RandomForestRegressor之中
    clf = linear_model.LogisticRegression(C=1.0, penalty='l1', tol=1e-6)
    clf.fit(X, y)
        
    clf
    

    good,很顺利,我们得到了一个model,如下:
    modeling

    先淡定!淡定!你以为把test.csv直接丢进model里就能拿到结果啊…骚年,图样图森破啊!我们的"test_data"也要做和"train_data"一样的预处理啊!!

    
    data_test = pd.read_csv("/Users/Hanxiaoyang/Titanic_data/test.csv")
    data_test.loc[ (data_test.Fare.isnull()), 'Fare' ] = 0
    # 接着我们对test_data做和train_data中一致的特征变换
    # 首先用同样的RandomForestRegressor模型填上丢失的年龄
    tmp_df = data_test[['Age','Fare', 'Parch', 'SibSp', 'Pclass']]
    null_age = tmp_df[data_test.Age.isnull()].as_matrix()
    # 根据特征属性X预测年龄并补上
    X = null_age[:, 1:]
    predictedAges = rfr.predict(X)
    data_test.loc[ (data_test.Age.isnull()), 'Age' ] = predictedAges
    
    data_test = set_Cabin_type(data_test)
    dummies_Cabin = pd.get_dummies(data_test['Cabin'], prefix= 'Cabin')
    dummies_Embarked = pd.get_dummies(data_test['Embarked'], prefix= 'Embarked')
    dummies_Sex = pd.get_dummies(data_test['Sex'], prefix= 'Sex')
    dummies_Pclass = pd.get_dummies(data_test['Pclass'], prefix= 'Pclass')
    
    
    df_test = pd.concat([data_test, dummies_Cabin, dummies_Embarked, dummies_Sex, dummies_Pclass], axis=1)
    df_test.drop(['Pclass', 'Name', 'Sex', 'Ticket', 'Cabin', 'Embarked'], axis=1, inplace=True)
    df_test['Age_scaled'] = scaler.fit_transform(df_test['Age'], age_scale_param)
    df_test['Fare_scaled'] = scaler.fit_transform(df_test['Fare'], fare_scale_param)
    df_test
    
    

    modeling

    不错不错,数据很OK,差最后一步了。
    下面就做预测取结果吧!!

    test = df_test.filter(regex='Age_.*|SibSp|Parch|Fare_.*|Cabin_.*|Embarked_.*|Sex_.*|Pclass_.*')
    predictions = clf.predict(test)
    result = pd.DataFrame({'PassengerId':data_test['PassengerId'].as_matrix(), 'Survived':predictions.astype(np.int32)})
    result.to_csv("/Users/Hanxiaoyang/Titanic_data/logistic_regression_predictions.csv", index=False)
    

    预测结果

    啧啧,挺好,格式正确,去make a submission啦啦啦!

    在Kaggle的Make a submission页面,提交上结果。如下:
    Kaggle排名

    0.76555,恩,结果还不错。毕竟,这只是我们简单分析处理过后出的一个baseline模型嘛。

    9.逻辑回归系统优化

    9.1 模型系数关联分析

    亲,你以为结果提交上了,就完事了?
    我不会告诉你,这只是万里长征第一步啊(泪牛满面)!!!这才刚撸完baseline model啊!!!还得优化啊!!!

    看过Andrew Ng老师的machine Learning课程的同学们,知道,我们应该分析分析模型现在的状态了,是过/欠拟合?,以确定我们需要更多的特征还是更多数据,或者其他操作。我们有一条很著名的learning curves对吧。

    不过在现在的场景下,先不着急做这个事情,我们这个baseline系统还有些粗糙,先再挖掘挖掘。

    • 首先,Name和Ticket两个属性被我们完整舍弃了(好吧,其实是因为这俩属性,几乎每一条记录都是一个完全不同的值,我们并没有找到很直接的处理方式)。

    • 然后,我们想想,年龄的拟合本身也未必是一件非常靠谱的事情,我们依据其余属性,其实并不能很好地拟合预测出未知的年龄。再一个,以我们的日常经验,小盆友和老人可能得到的照顾会多一些,这样看的话,年龄作为一个连续值,给一个固定的系数,应该和年龄是一个正相关或者负相关,似乎体现不出两头受照顾的实际情况,所以,说不定我们把年龄离散化,按区段分作类别属性会更合适一些。

    上面只是我瞎想的,who knows是不是这么回事呢,老老实实先把得到的model系数和feature关联起来看看。

    pd.DataFrame({"columns":list(train_df.columns)[1:], "coef":list(clf.coef_.T)})
    

    LR模型系数

    首先,大家回去前两篇文章里瞄一眼公式就知道,这些系数为正的特征,和最后结果是一个正相关,反之为负相关。

    我们先看看那些权重绝对值非常大的feature,在我们的模型上:

    • Sex属性,如果是female会极大提高最后获救的概率,而male会很大程度拉低这个概率。
    • Pclass属性,1等舱乘客最后获救的概率会上升,而乘客等级为3会极大地拉低这个概率。
    • 有Cabin值会很大程度拉升最后获救概率(这里似乎能看到了一点端倪,事实上从最上面的有无Cabin记录的Survived分布图上看出,即使有Cabin记录的乘客也有一部分遇难了,估计这个属性上我们挖掘还不够)
    • Age是一个负相关,意味着在我们的模型里,年龄越小,越有获救的优先权(还得回原数据看看这个是否合理
    • 有一个登船港口S会很大程度拉低获救的概率,另外俩港口压根就没啥作用(这个实际上非常奇怪,因为我们从之前的统计图上并没有看到S港口的获救率非常低,所以也许可以考虑把登船港口这个feature去掉试试)。
    • 船票Fare有小幅度的正相关(并不意味着这个feature作用不大,有可能是我们细化的程度还不够,举个例子,说不定我们得对它离散化,再分至各个乘客等级上?)

    噢啦,观察完了,我们现在有一些想法了,但是怎么样才知道,哪些优化的方法是promising的呢?

    因为test.csv里面并没有Survived这个字段(好吧,这是废话,这明明就是我们要预测的结果),我们无法在这份数据上评定我们算法在该场景下的效果…

    而『每做一次调整就make a submission,然后根据结果来判定这次调整的好坏』其实是行不通的…

    9.2 交叉验证

    重点又来了:

    『要做交叉验证(cross validation)!』
    『要做交叉验证(cross validation)!』
    『要做交叉验证(cross validation)!』

    恩,重要的事情说三遍。我们通常情况下,这么做cross validation:把train.csv分成两部分,一部分用于训练我们需要的模型,另外一部分数据上看我们预测算法的效果。

    我们用scikit-learn的cross_validation来帮我们完成小数据集上的这个工作。

    先简单看看cross validation情况下的打分

    from sklearn import cross_validation
    
     #简单看看打分情况
    clf = linear_model.LogisticRegression(C=1.0, penalty='l1', tol=1e-6)
    all_data = df.filter(regex='Survived|Age_.*|SibSp|Parch|Fare_.*|Cabin_.*|Embarked_.*|Sex_.*|Pclass_.*')
    X = all_data.as_matrix()[:,1:]
    y = all_data.as_matrix()[:,0]
    print cross_validation.cross_val_score(clf, X, y, cv=5)
    

    结果是下面酱紫的:
    [0.81564246 0.81005587 0.78651685 0.78651685 0.81355932]

    似乎比Kaggle上的结果略高哈,毕竟用的是不是同一份数据集评估的。

    等等,既然我们要做交叉验证,那我们干脆先把交叉验证里面的bad case拿出来看看,看看人眼审核,是否能发现什么蛛丝马迹,是我们忽略了哪些信息,使得这些乘客被判定错了。再把bad case上得到的想法和前头系数分析的合在一起,然后逐个试试。

    下面我们做数据分割,并且在原始数据集上瞄一眼bad case:

    # 分割数据,按照 训练数据:cv数据 = 7:3的比例
    split_train, split_cv = cross_validation.train_test_split(df, test_size=0.3, random_state=0)
    train_df = split_train.filter(regex='Survived|Age_.*|SibSp|Parch|Fare_.*|Cabin_.*|Embarked_.*|Sex_.*|Pclass_.*')
    # 生成模型
    clf = linear_model.LogisticRegression(C=1.0, penalty='l1', tol=1e-6)
    clf.fit(train_df.as_matrix()[:,1:], train_df.as_matrix()[:,0])
    
    # 对cross validation数据进行预测
    
    cv_df = split_cv.filter(regex='Survived|Age_.*|SibSp|Parch|Fare_.*|Cabin_.*|Embarked_.*|Sex_.*|Pclass_.*')
    predictions = clf.predict(cv_df.as_matrix()[:,1:])
    
    origin_data_train = pd.read_csv("/Users/HanXiaoyang/Titanic_data/Train.csv")
    bad_cases = origin_data_train.loc[origin_data_train['PassengerId'].isin(split_cv[predictions != cv_df.as_matrix()[:,0]]['PassengerId'].values)]
    bad_cases
    

    我们判定错误的 bad case 中部分数据如下:
    预测错误的原始数据

    大家可以自己跑一遍试试,拿到bad cases之后,仔细看看。也会有一些猜测和想法。其中会有一部分可能会印证在系数分析部分的猜测,那这些优化的想法优先级可以放高一些。

    现在有了"train_df" 和 “vc_df” 两个数据部分,前者用于训练model,后者用于评定和选择模型。可以开始可劲折腾了。

    我们随便列一些可能可以做的优化操作:

    • Age属性不使用现在的拟合方式,而是根据名称中的『Mr』『Mrs』『Miss』等的平均值进行填充。
    • Age不做成一个连续值属性,而是使用一个步长进行离散化,变成离散的类目feature。
    • Cabin再细化一些,对于有记录的Cabin属性,我们将其分为前面的字母部分(我猜是位置和船层之类的信息) 和 后面的数字部分(应该是房间号,有意思的事情是,如果你仔细看看原始数据,你会发现,这个值大的情况下,似乎获救的可能性高一些)。
    • Pclass和Sex俩太重要了,我们试着用它们去组出一个组合属性来试试,这也是另外一种程度的细化。
    • 单加一个Child字段,Age<=12的,设为1,其余为0(你去看看数据,确实小盆友优先程度很高啊)
    • 如果名字里面有『Mrs』,而Parch>1的,我们猜测她可能是一个母亲,应该获救的概率也会提高,因此可以多加一个Mother字段,此种情况下设为1,其余情况下设为0
    • 登船港口可以考虑先去掉试试(Q和C本来就没权重,S有点诡异)
    • 把堂兄弟/兄妹 和 Parch 还有自己 个数加在一起组一个Family_size字段(考虑到大家族可能对最后的结果有影响)
    • Name是一个我们一直没有触碰的属性,我们可以做一些简单的处理,比如说男性中带某些字眼的(‘Capt’, ‘Don’, ‘Major’, ‘Sir’)可以统一到一个Title,女性也一样。

    大家接着往下挖掘,可能还可以想到更多可以细挖的部分。我这里先列这些了,然后我们可以使用手头上的"train_df"和"cv_df"开始试验这些feature engineering的tricks是否有效了。

    试验的过程比较漫长,也需要有耐心,而且我们经常会面临很尴尬的状况,就是我们灵光一闪,想到一个feature,然后坚信它一定有效,结果试验下来,效果还不如试验之前的结果。恩,需要坚持和耐心,以及不断的挖掘。

    我最好的结果是在『Survived~C(Pclass)+C(Title)+C(Sex)+C(Age_bucket)+C(Cabin_num_bucket)Mother+Fare+Family_Size』下取得的,结果如下(抱歉,博主君commit的时候手抖把页面关了,于是没截着图,下面这张图是在我得到最高分之后,用这次的结果重新make commission的,截了个图,得分是0.79426,不是目前我的最高分哈,因此排名木有变…):

    做完feature engineering调整之后的结果

    9.3 learning curves

    有一个很可能发生的问题是,我们不断地做feature engineering,产生的特征越来越多,用这些特征去训练模型,会对我们的训练集拟合得越来越好,同时也可能在逐步丧失泛化能力,从而在待预测的数据上,表现不佳,也就是发生过拟合问题。

    从另一个角度上说,如果模型在待预测的数据上表现不佳,除掉上面说的过拟合问题,也有可能是欠拟合问题,也就是说在训练集上,其实拟合的也不是那么好。

    额,这个欠拟合和过拟合怎么解释呢。这么说吧:

    • 过拟合就像是你班那个学数学比较刻板的同学,老师讲过的题目,一字不漏全记下来了,于是老师再出一样的题目,分分钟精确出结果。but数学考试,因为总是碰到新题目,所以成绩不咋地。
    • 欠拟合就像是,咳咳,和博主level差不多的差生。连老师讲的练习题也记不住,于是连老师出一样题目复习的周测都做不好,考试更是可想而知了。

    而在机器学习的问题上,对于过拟合欠拟合两种情形。我们优化的方式是不同的。

    对过拟合而言,通常以下策略对结果优化是有用的:

    • 做一下feature selection,挑出较好的feature的subset来做training
    • 提供更多的数据,从而弥补原始数据的bias问题,学习到的model也会更准确

    而对于欠拟合而言,我们通常需要更多的feature,更复杂的模型来提高准确度。

    著名的learning curve可以帮我们判定我们的模型现在所处的状态。我们以样本数为横坐标,训练和交叉验证集上的错误率作为纵坐标,两种状态分别如下两张图所示:过拟合(overfitting/high variace),欠拟合(underfitting/high bias)

    过拟合

    欠拟合

    我们也可以把错误率替换成准确率(得分),得到另一种形式的learning curve(sklearn 里面是这么做的)。

    回到我们的问题,我们用scikit-learn里面的learning_curve来帮我们分辨我们模型的状态。举个例子,这里我们一起画一下我们最先得到的baseline model的learning curve。

    import numpy as np
    import matplotlib.pyplot as plt
    from sklearn.learning_curve import learning_curve
    
    # 用sklearn的learning_curve得到training_score和cv_score,使用matplotlib画出learning curve
    def plot_learning_curve(estimator, title, X, y, ylim=None, cv=None, n_jobs=1, 
                            train_sizes=np.linspace(.05, 1., 20), verbose=0, plot=True):
        """
        画出data在某模型上的learning curve.
        参数解释
        ----------
        estimator : 你用的分类器。
        title : 表格的标题。
        X : 输入的feature,numpy类型
        y : 输入的target vector
        ylim : tuple格式的(ymin, ymax), 设定图像中纵坐标的最低点和最高点
        cv : 做cross-validation的时候,数据分成的份数,其中一份作为cv集,其余n-1份作为training(默认为3份)
        n_jobs : 并行的的任务数(默认1)
        """
        train_sizes, train_scores, test_scores = learning_curve(
            estimator, X, y, cv=cv, n_jobs=n_jobs, train_sizes=train_sizes, verbose=verbose)
        
        train_scores_mean = np.mean(train_scores, axis=1)
        train_scores_std = np.std(train_scores, axis=1)
        test_scores_mean = np.mean(test_scores, axis=1)
        test_scores_std = np.std(test_scores, axis=1)
        
        if plot:
            plt.figure()
            plt.title(title)
            if ylim is not None:
                plt.ylim(*ylim)
            plt.xlabel(u"训练样本数")
            plt.ylabel(u"得分")
            plt.gca().invert_yaxis()
            plt.grid()
        
            plt.fill_between(train_sizes, train_scores_mean - train_scores_std, train_scores_mean + train_scores_std, 
                             alpha=0.1, color="b")
            plt.fill_between(train_sizes, test_scores_mean - test_scores_std, test_scores_mean + test_scores_std, 
                             alpha=0.1, color="r")
            plt.plot(train_sizes, train_scores_mean, 'o-', color="b", label=u"训练集上得分")
            plt.plot(train_sizes, test_scores_mean, 'o-', color="r", label=u"交叉验证集上得分")
        
            plt.legend(loc="best")
            
            plt.draw()
            plt.show()
            plt.gca().invert_yaxis()
        
        midpoint = ((train_scores_mean[-1] + train_scores_std[-1]) + (test_scores_mean[-1] - test_scores_std[-1])) / 2
        diff = (train_scores_mean[-1] + train_scores_std[-1]) - (test_scores_mean[-1] - test_scores_std[-1])
        return midpoint, diff
    
    plot_learning_curve(clf, u"学习曲线", X, y)
    

    学习曲线

    在实际数据上看,我们得到的learning curve没有理论推导的那么光滑哈,但是可以大致看出来,训练集和交叉验证集上的得分曲线走势还是符合预期的。

    目前的曲线看来,我们的model并不处于overfitting的状态(overfitting的表现一般是训练集上得分高,而交叉验证集上要低很多,中间的gap比较大)。因此我们可以再做些feature engineering的工作,添加一些新产出的特征或者组合特征到模型中。

    10.模型融合(model ensemble)

    好了,终于到这一步了,我们要祭出机器学习/数据挖掘上通常最后会用到的大杀器了。恩,模型融合。

    『强迫症患者』打算继续喊喊口号…
    『模型融合(model ensemble)很重要!』
    『模型融合(model ensemble)很重要!』
    『模型融合(model ensemble)很重要!』
    重要的事情说三遍,恩,噢啦。

    先解释解释,一会儿再回到我们的问题上哈。
    啥叫模型融合呢,我们还是举几个例子直观理解一下好了。

    大家都看过知识问答的综艺节目中,求助现场观众时候,让观众投票,最高的答案作为自己的答案的形式吧,每个人都有一个判定结果,最后我们相信答案在大多数人手里。

    再通俗一点举个例子。你和你班某数学大神关系好,每次作业都『模仿』他的,于是绝大多数情况下,他做对了,你也对了。突然某一天大神脑子犯糊涂,手一抖,写错了一个数,于是…恩,你也只能跟着错了。
    我们再来看看另外一个场景,你和你班5个数学大神关系都很好,每次都把他们作业拿过来,对比一下,再『自己做』,那你想想,如果哪天某大神犯糊涂了,写错了,but另外四个写对了啊,那你肯定相信另外4人的是正确答案吧?

    最简单的模型融合大概就是这么个意思,比如分类问题,当我们手头上有一堆在同一份数据集上训练得到的分类器(比如logistic regression,SVM,KNN,random forest,神经网络),那我们让他们都分别去做判定,然后对结果做投票统计,取票数最多的结果为最后结果

    bingo,问题就这么完美的解决了。

    模型融合可以比较好地缓解,训练过程中产生的过拟合问题,从而对于结果的准确度提升有一定的帮助。

    话说回来,回到我们现在的问题。你看,我们现在只讲了logistic regression,如果我们还想用这个融合思想去提高我们的结果,我们该怎么做呢?

    既然这个时候模型没得选,那咱们就在数据上动动手脚咯。大家想想,如果模型出现过拟合现在,一定是在我们的训练上出现拟合过度造成的对吧。

    那我们干脆就不要用全部的训练集,每次取训练集的一个subset,做训练,这样,我们虽然用的是同一个机器学习算法,但是得到的模型却是不一样的;同时,因为我们没有任何一份子数据集是全的,因此即使出现过拟合,也是在子训练集上出现过拟合,而不是全体数据上,这样做一个融合,可能对最后的结果有一定的帮助。对,这就是常用的Bagging。

    我们用scikit-learn里面的Bagging来完成上面的思路,过程非常简单。代码如下:

    from sklearn.ensemble import BaggingRegressor
    
    train_df = df.filter(regex='Survived|Age_.*|SibSp|Parch|Fare_.*|Cabin_.*|Embarked_.*|Sex_.*|Pclass.*|Mother|Child|Family|Title')
    train_np = train_df.as_matrix()
    
    # y即Survival结果
    y = train_np[:, 0]
    
    # X即特征属性值
    X = train_np[:, 1:]
    
    # fit到BaggingRegressor之中
    clf = linear_model.LogisticRegression(C=1.0, penalty='l1', tol=1e-6)
    bagging_clf = BaggingRegressor(clf, n_estimators=20, max_samples=0.8, max_features=1.0, bootstrap=True, bootstrap_features=False, n_jobs=-1)
    bagging_clf.fit(X, y)
    
    test = df_test.filter(regex='Age_.*|SibSp|Parch|Fare_.*|Cabin_.*|Embarked_.*|Sex_.*|Pclass.*|Mother|Child|Family|Title')
    predictions = bagging_clf.predict(test)
    result = pd.DataFrame({'PassengerId':data_test['PassengerId'].as_matrix(), 'Survived':predictions.astype(np.int32)})
    result.to_csv("/Users/HanXiaoyang/Titanic_data/logistic_regression_bagging_predictions.csv", index=False)
    

    然后你再Make a submission,恩,发现对结果还是有帮助的。

    ensemble之后的结果

    11.总结

    文章稍微有点长,非常感谢各位耐心看到这里。
    总结的部分,我就简短写几段,出现的话,很多在文中有对应的场景,大家有兴趣再回头看看。

    对于任何的机器学习问题,不要一上来就追求尽善尽美,先用自己会的算法撸一个baseline的model出来,再进行后续的分析步骤,一步步提高

    在问题的结果过程中:

    • 『对数据的认识太重要了!』
    • 『数据中的特殊点/离群点的分析和处理太重要了!』
    • 『特征工程(feature engineering)太重要了!』
    • 『模型融合(model ensemble)太重要了!』

    本文中用机器学习解决问题的过程大概如下图所示:
    机器学习解决问题的过程

    12.关于数据和代码

    本文中的数据和代码已经上传至github中,欢迎大家下载和自己尝试。

    展开全文
  • 机器学习逻辑回归Python代码实现

    千次阅读 2019-05-01 08:15:50
    逻辑回归模型(S 形函数): 中间变量: sigmoid函数的输出值永远在0 到1 之间: sigmoid函数的输出值永远在0 到1 之间: 逻辑回归模型的概率解释: 对于给定的输入变量x,根据选择的参数θ,计算输出变量y=1 ...
    分类问题不用线性回归的原因:
    1. 对于分类问题,y 取值为0 或者1。
    2. 如果使用线性回归,那么线性回归模型的输出值可能远大于1,或者远小于0。
      导致代价函数很大。
    逻辑回归模型(S 形函数):

    逻辑回归模型(S 形函数)

    中间变量:

    中间变量

    sigmoid函数的输出值永远在0 到1 之间:

    sigmoid函数的输出值永远在0 到1 之间
    sigmoid函数的输出值永远在0 到1 之间:
    在这里插入图片描述
    逻辑回归模型的概率解释:
    对于给定的输入变量x,根据选择的参数θ,计算输出变量y=1 的可能性(estimated probability)即:
    在这里插入图片描述
    例如:如果对于给定的x,通过已经确定的参数计算得出hθ(x)=0.7,则表示有70%的几率y 为正向类,相应地y 为负向类的几率为1-0.7=0.3

    逻辑回归的代价函数(交叉熵):

    逻辑回归的代价函数(交叉熵)
    该代价函数J(θ)是一个凸函数,有全局最优值;
    因为代价函数是凸函数,无论在哪里初始化,最终达到这个凸函数的最小值点。

    逻辑回归Python代码实现

    ex2data5.txt文件提取码:3d33)

    import numpy as np
    import matplotlib.pyplot as plt
    import matplotlib as mpl
    mpl.rcParams['font.sans-serif'] = ['SimHei']  # 显示中文
    mpl.rcParams['axes.unicode_minus'] = False  # 能正确显示正负号
    
    # 数据处理
    # 加载数据
    data = np.loadtxt('ex2data5.txt', delimiter=',')
    # 切分
    # 参数一,被切分的矩阵
    # 参数二代表如何切分,[-1]代表-1之前的归为第一个返回值,其后归为第二个返回值
    # 参数三,axis=0是横向切分,切分样本;axis=1是纵向切分,切分的是特征
    x, y = np.split(data, [-1], axis=1)
    
    # 特征缩放
    mean = np.mean(x, 0)  # 平均数
    sigma = np.std(x, 0, ddof=1)  # 标准差
    x = (x-mean)/sigma  # 标准化特征缩放
    
    # 拼接
    m = len(x)
    x = np.c_[np.ones((m, 1)), x]
    y = np.c_[y]
    
    # 切分训练集和测试集
    num = int(m*0.7)
    trainx, testx=np.split(x, [num])
    trainy, testy=np.split(y, [num])
    
    # sigmoid函数
    def sigmoid(z):
        return 1.0/(1+np.exp(-z))
    
    # 模型
    def model(x, theta):
        z = x.dot(theta)
        h = sigmoid(z)   # 用sigmoid函数将连续值映射为0-1之间的概率值
        return h
    
    # 交叉熵代价
    def cost_function(h, y):
        m = len(h)
        J = -1.0/m*np.sum(y*np.log(h)+(1-y)*np.log(1-h)) 
        return J
    
    # 梯度下降函数
    def gradsDesc(x, y, alpha=0.001, count_iter=15000, lamda=0.5):
        m, n = x.shape
        theta = np.zeros((n, 1))
        jarr = np.zeros(count_iter)
    
        for i in range(count_iter):
            h = model(x, theta)
            e = h - y
            jarr[i] = cost_function(h, y)
            deltatheta = 1.0/m*x.T.dot(e)
            theta -= alpha*deltatheta
    
        return jarr, theta
    
    # 模型精度,准确率
    def accuracy(y, h):
        m = len(y)
        count = 0  #  统计预测值与真实值一致的样本个数
        for i in range(m):
            h[i] = np.where(h[i]>=0.5,1,0)  # 将预测值从概率值转换为0或1
            if h[i] == y[i]:
                count += 1
    
        return count/m
    
    # 画图
    def draw(x, y, theta):
        zeros = y[:,0]==0   # 选取y=0的行,其值为true
        ones = y[:,0]==1  # 选取y=1的行,其值为true
    
        # 画散点图
        plt.scatter(x[zeros,1],x[zeros,2],c='b',label='负向类')   # 画负向类的散点图
        plt.scatter(x[ones,1],x[ones,2], c='r', label='正向类')   # 画正向类的散点图
    
        # 画分界线
        # 取x1的最小值和最大值
        minx1 = x[:,1].min()
        maxx1 = x[:,1].max()
    
        # 计算x1的最大值和最小值在z=0上的对应的x2值
        minx1_x2 = -((theta[0]+theta[1]*minx1)/theta[2])
        maxx1_x2 = -((theta[0]+theta[1]*maxx1)/theta[2])
    
        # 以两个点坐标,画出z=0的决策边界
        plt.plot([minx1,maxx1], [minx1_x2, maxx1_x2])
        plt.title('测试精度:%0.2f' % (accuracy(testy, testh)))
        plt.legend()
        plt.show()
    
    # 训练模型
    jarr, theta = gradsDesc(trainx, trainy)
    
    # 计算测试值预测值
    testh = model(testx, theta)
    
    # 计算测试集预测精度
    print('测试集预测精度:', accuracy(testy, testh))
    # print('测试集预测值:', testh)
    
    #画图
    draw(x, y,theta)
    
    # 画sigmoid函数
    # a = np.arange(-10, 10)
    # print(a)
    # b = sigmoid(a)
    # plt.plot(a,b)
    # plt.show()
    

    逻辑回归

    展开全文
  • 虽然逻辑回归算法的名字中有回归二字,但是它却不是回归算法,它其实是分类算法。它通常是利用已知的自变量来预测一个离散型因变量的值。简单来说,它就是通过拟合一个逻辑函数来预测一个事件发生的概率。所以它预测...

    https://www.toutiao.com/a6630407688360575502/

     

    2018-12-04 22:46:48

    逻辑回归算法

    虽然逻辑回归算法的名字中有回归二字,但是它却不是回归算法,它其实是分类算法。它通常是利用已知的自变量来预测一个离散型因变量的值。简单来说,它就是通过拟合一个逻辑函数来预测一个事件发生的概率。所以它预测的是一个概率值,自然它的输出值应该在0到1之间。要想实现输出值的范围在0到1,我们可以使用一个简单的函数来做到,这个函数就是sigmoid函数。

    sigmoid函数

    基于机器学习逻辑回归算法完成癌症病人的肿瘤是否良性的判断

    sigmoid函数图像

    sigmoid函数如上图所示,我们可以看出它的值域在0~1之间。逻辑回归算法和Sigmod函数结合起来可以实现逻辑回归分类器,我们可以在每一个样本特征上都乘以一个回归系数,然后将所有的结果值相加,将总和代入Sigmoid函数,进而得到一个范围在0~1之间的数值。任何大于0.5的数据被分为y=1类,小于0.5被归为y=0类。

    基于机器学习逻辑回归算法完成癌症病人的肿瘤是否良性的判断

    逻辑回归分类器

    以上就是逻辑回归分类器的计算过程,我们来分析一下这个计算过程,我们输入样本x,然后样本特征xi乘以一个回归系数θj,我们将所有的结果进行相加,其实就是θ的转置*X,然后我们再将求和结果带入sigmoid函数中,最终的结果就是hθ(x)。如果hθ(x)大于0.5,那么这个样本我们就认为y=1,如果如果hθ(x)小于0.5,那么这个样本我们就认为y=0,这就是逻辑回归分类器的核心思想。

    使用逻辑回归分类器完成癌症良性和恶性的判别

    基于机器学习逻辑回归算法完成癌症病人的肿瘤是否良性的判断

    癌症病人样本

    现在我们有一个如上所示的癌症病人的样本数据,其中O表示良性,而X表示恶性,现在我们的任务是通过逻辑回归分类算法学习出一条决策边界,从而将这两个样本给分开,当我们拥有这条决策边界之后,以后当再有新的样本的时候,我们就可以直接代入我们的模型中,就可以得出这个病人是良性还是恶性了。具体来说我们需要学习出如下所示的决策边界:

    基于机器学习逻辑回归算法完成癌症病人的肿瘤是否良性的判断

    逻辑回归分类器的决策边界

    我们可以看到这条蓝色的决策边界完成分开了两种不同的样本,我们的目的就是训练出这样的一条分类边界那么以后我们的模型就可以判断病人是否患有恶性肿瘤了,要想训练出这样的分类边界,我们可以使用逻辑回归的梯度下降算法

    逻辑回归的梯度下降算法

    基于机器学习逻辑回归算法完成癌症病人的肿瘤是否良性的判断

    分类边界方程

    我们设我们的分类边界的方程如上所示,我们将这个分类边界带入到sigmoid函数中,我们就可以得出逻辑回归分类器的模型表示。

    基于机器学习逻辑回归算法完成癌症病人的肿瘤是否良性的判断

    逻辑回归分类器的模型

    当我们带入样本特征x1、x2的时候,如果hθ(x)的结果大于0.5,那么我们可以认为这个样本类别为y=1,如果hθ(x)的结果小于0.5,那么我们可以认为这个样本的类别为y=0。

    现在模型已经有了,现在的问题是模型中存在未知的参数θ0、θ1和θ2,所以我们现在的任务是通过已知数据,从而训练出最好的参数θ,要想完成这个任务,我们需要使用梯度下降算法。

    基于机器学习逻辑回归算法完成癌症病人的肿瘤是否良性的判断

    梯度下降算法

    经过梯度下将算法之后,我们可以得出适合已经训练数据的最佳参数θ,假设最好的参数θ0=-3、θ1=1、θ2=1,那么此时我们的逻辑回归分类器的莫模型方程就是

    基于机器学习逻辑回归算法完成癌症病人的肿瘤是否良性的判断

    逻辑回归分类器的模型

    有了这个模型之后,我们就可以带入未知的样本特征x1和x2,从而得出未知病人样本是否是恶性肿瘤,具体来说如果带入之后如果hθ(x)>0.5就是恶性,而hθ(x)<0.5就是良性,这就是逻辑回归算法在分类中的应用。

    展开全文
  • 机器学习-逻辑回归分析(Python)

    万次阅读 多人点赞 2018-11-12 00:16:09
    回归和分类方法是机器学习中经常用到的方法,本文首先介绍这两种方法的区别和联系,然后对分类方法中的逻辑回归进行较详细的说明(包括其基本原理及评估指标),最后结合案例介绍如何利用Python进行逻辑回归分析。...
  • 机器学习逻辑回归原理介绍

    万次阅读 2019-07-05 21:05:12
    有些文献中译为“逻辑回归”,但中文“逻辑”与 logistic 和 logit 的含义相去甚远,因此下文中直接使用 logistic 表示。Logistic 回归的优点是计算代价不高,容易理解和实现;缺点是容易欠拟合,分类精度可能不高。...
  • 目录1、背景2、效果图3、本次实验整体流程4、这里用词向量,而不是TF-IDF预处理后的向量5、源代码6、知识点普及6.1逻辑回归优点6.2逻辑回归缺点 1、背景 最近的项目中,用到了很多机器学习的算法,每个机器学习的...
  • 一、逻辑回归模型 逻辑回归主要应用于二分类问题,其主要思想是:根据现有数据对分类边界线建立回归公式,以此进行分类。逻辑回归把线性回归的输出集输入到simoid函数 中得到: . sigmoid函数自变量为实数集...
  • 前言:本篇博文主要介绍逻辑回归(logistic regression),首先介绍相关的基础概念和原理,然后通过Python...特别强调,其中大多理论知识来源于《统计学习方法_李航》和斯坦福课程翻译笔记以及Coursera机器学习课程。
  • 机器学习算法-逻辑回归一. 逻辑回归模型1.1 逻辑回归定义1.2 逻辑回归模型二. 代价函数求解2.1 定义代价函数的方法2.2 代价函数求解方法-梯度下降三. Sklearn 参数说明四. 常见问题参考 一. 逻辑回归模型 1.1 逻辑...
  • 机器学习——Python实现逻辑回归

    千次阅读 2017-01-10 09:04:00
    逻辑回归是一项可用于预测二分类结果(binary outcome)的统计技术,广泛...逻辑回归使用简单且非常有效,你可以在许多机器学习、应用统计的书中的前几章中找到个关于逻辑回归的介绍。逻辑回归在许多统计课程中都会用到。
  • 引言:逻辑回归是最简单的机器学习模型,常常应用于各种简单的任务中。这里记录逻辑回归的背景以及学习方法,权当自己的学习记录总结。
  • 机器学习:线性回归和逻辑回归

    千次阅读 2018-08-29 20:48:19
    线性回归和逻辑回归的区别: 两者都属于回归算法,线性回归主要用来解决连续值预测的问题,逻辑回归用来解决分类的问题,输出的属于某个类别的概率,工业界经常会用逻辑回归来做排序。在SVM、GBDT、AdaBoost算法...
  • 逻辑斯蒂回归实质是对数几率回归(广义的线性回归),是用来解决分类问题的。 其中sigmoid用来解决二分类问题,softmax解决多分类问题,sigmoid是softmax的特殊情况。 数学建模直接针对分类可能性建模。 参数学习...
  • 【5】机器学习之简单美:逻辑回归

    千次阅读 2016-06-01 12:15:00
    逻辑回归(Logistic Regression)是机器学习中的一种分类模型,由于算法的简单和高效,在实际中应用非常广泛。本文作为美团机器学习InAction系列中的一篇,主要关注逻辑回归算法的数学模型和参数求解方法,最后也会...
  • 机器学习逻辑回归 LR 算法 整理

    千次阅读 2018-01-20 11:38:12
    有了 Sigmoid 函数之后,由于其值取值范围在[0,1]。就可以将其视为类 1 的后验概率估计 p(y=1|X)。就是如果有一个测试点 x,就可以用Sigmoid函数算出来的结果...1.逻辑斯蒂回归模型 LR模型主要用于分类模型,细...
  • 机器学习逻辑回归代码解读

    千次阅读 2020-03-12 21:56:58
    为什么是梯度上升以及为什么这么求,大家可以看别人的博客,李航的统计学习书也比较详细,李宏毅的视频里也介绍了。这里我就懒得再写了。 然后再看第三个函数:关于随机梯度上升法。 def stocGradAscent0(dataMatrix...
  • 注:最近开始学习《人工智能》选修课,老师提纲挈领的介绍了一番,听完课只了解了个大概,剩下的细节只能自己...从大的类别上来说,逻辑回归是一种有监督的统计学习方法,主要用于对样本进行分类。 在线性回归模...
  • 1.逻辑回归与多项逻辑回归1.1什么是逻辑回归逻辑回归,可以说是在线性回归的基础上加上一个sigmoid函数,将线性回归产生的值归一化到[0-1]区间内。sigmoid函数如下:​ sigmoid(x)=11+e−xsigmoid(x)=\frac{1}{1+e...
  • 文章目录1 逻辑回归算法简介2 算法原理2.1 线性回归2.2 逻辑回归2.3 损失函数(cost function)2.4 梯度下降法(1) 直观理解(2) 梯度下降法——代数法(3) 梯度下降的种类2.5 线性回归与逻辑回归的区别3 实验3.1 逻辑...
  • 几个常用机器学习算法 - 逻辑回归

    千次阅读 2016-11-02 19:55:26
    1 回归在数学上来说,回归是给定一个点集,然后用一条曲线去拟合。 如果这条曲线是一条直线,那就被称为线性回归;如果是一条二次曲线,就被称为二次回归回归还有很多的变种,如locally weighted回归,logistic...
  • 开一个系列来记录自己在学习机器学习算法原理中的心得与感悟,首先从逻辑回归开始写起吧。 逻辑回归在维基百科的定义是Logistic回归是一种统计模型,其基本形式是使用Logistic函数来对二元因变量建模,尽管存在...
  • 机器学习线性回归学习心得Data science with the kind of power it gives you to analyze each and every bit of data you have at your disposal, to make smart & intelligent business decisions, is ...
  • 2) 假设的模型,即一个函数,这个函数里含有未知的参数,通过学习,可以估计出参数。然后利用这个模型去预测/分类新的数据。 1. 线性回归 假设 特征 和 结果 都满足线性。即不大于一次方。这个是针对 收集的数据而...
  • 前面几篇逻辑回归的例子有些是人造出来的,有些是比较正规的,但数据都比较完整,没有缺失的属性。虽然我们在很多数据上取到的非常好的效果,但总感觉好像不够味,不像实战。所有的数据下载地址:...
  • 使用10折交叉验证法和留一法评测对率回归分类器标题有点长哈……这是第一次作业,来自周志华《机器学习》作业3.4,题目如下: 选择两个UCI数据集,比较10折交叉验证法和留一法所估计出的对率回归(逻辑回归)的错误...
  • 逻辑回归需要掌握的知识点 知道逻辑回归的损失函数 知道逻辑回归的优化方法 知道sigmoid函数 知道逻辑回归的应用场景 应用LogisticRegression实现逻辑回归预测 知道精确率、召回率指标的区别 知道如何解决样本不...
  • 本文主要记录我在学习逻辑回归时的心得笔记,从假设函数、代价函数、优化方法等方面介绍了逻辑回归。
  • 本文主要针对一个简单的机器学习算法逻辑斯蒂回归模型进行相关的讲解。主要内容包括:逻辑斯蒂回归模型定义及来源、二项逻辑斯蒂回归模型形式与推导、二项逻辑斯蒂回归模型的参数估计与多项逻辑斯蒂回归模型推广。 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 27,882
精华内容 11,152
关键字:

统计机器学习逻辑回归