美文网首页机器学习
Python机器学习之线性模型

Python机器学习之线性模型

作者: 一只怂货小脑斧 | 来源:发表于2020-09-15 11:49 被阅读0次

    一、线性模型基本概念

     线性模型不是指某一个模型,而是一类模型。在机器学习领域,常用的线性模型包括,线性回归、岭回归、套索回归、逻辑回归和线性SVC等。

    1.线性模型的图形表示——拟合两点

     假设有两个点(1,3)和(4,5),用python计算出穿过两点的直线方程,并画出图形。

    #求解穿过点的直线方程,并绘图
    import numpy as np
    import matplotlib.pyplot as plt
    from sklearn.linear_model import LinearRegression #导入线性回归模型
    #输入两点的横坐标
    X = [[1], [4]]
    #输入两点的纵坐标
    y = [3, 5]
    
    #用线性模型拟合这两个点
    lr = LinearRegression().fit(X, y)
    
    #画出两个点和直线图形
    z = np.linspace(0, 5, 20)
    plt.scatter(X, y, s=80)
    plt.plot(z, lr.predict(z.reshape(-1, 1), c='k'))
    #设定图片标题
    plt.title('Straight Line')
    #输出直线方程
    print('直线方程为:')
    print('==========================')
    print('y = {:.3f}'.format(lr.coef_[0]), 'x',' + {:.3f}'.format(lr.intercept_))
    plt.show()
    

    执行结果如下,直线穿过两个点:

    直线方程为:
    ==========================
    y = 0.667 x  + 2.333
    
    4.1line_equation.png

    注释1:

    numpy.linspace 用来生成等差数列

    函数原型:numpy.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None, axis=0)

    参数解释
     start:返回样本数据开始点
     stop:返回样本数据结束点
     num:生成的样本数据量,默认为50
     endpoint:True则包含stop;False则不包含stop
     retstep:If True, return (samples, step), where step is the spacing between samples.(即如果为True则结果会给出数据间隔)
     dtype:输出数组类型
     axis:0(默认)或-1
    返回类型
    Return evenly spaced numbers over a specified interval.
    (在start和stop之间返回均匀间隔的数据)

    Returns num evenly spaced samples, calculated over the interval [start, stop].
    (返回的是 [start, stop]之间的均匀分布)
    The endpoint of the interval can optionally be excluded.
    Changed in version 1.16.0: Non-scalar start and stop are now supported.
    (可以选择是否排除间隔的终点)

    注释2:

    reshape(行,列) 可以根据指定的数值将数据转换为特定的行数和列数,就是转换成矩阵。

    如果 reshape(-1,1)或者 reshape(1,-1)意味着转换成为一列或者一行

    注释3:

    sklearn.linear_model.LogisticRegression

    函数原型sklearn.linear_model.LogisticRegression(penalty=’l2’, dual=False, tol=0.0001, C=1.0, fit_intercept=True, intercept_scaling=1, class_weight=None, random_state=None, solver=’liblinear’, max_iter=100, multi_class=’ovr’, verbose=0, warm_start=False, n_jobs=1)
    参数解释
    penalty: 一个字符串,指定了正则化策略。可选 l2 、l1
    dual : 一个布尔值。如果为True,则求解对偶形式(只在penalty=‘l2’且solver=‘liblinear’有对偶形式),如果为False,则求解原始形式。
    C : 一个浮点数。它指定了罚项系数的倒数。如果它的值越小,则正则化项越大。
    fit_intercept : 一个布尔值,指定是否需要计算b值。如果为False,那么不计算b值。
    intercept_scaling : 一个浮点数。只有当solver=‘liblinear’才有意义。当采用fit_intercept时,相当于人造了一个特征,该特征恒为1,其权重为b。在计算正则化项的时候,该人造特征也被考虑了。因此为了降低这个人造特征的影响,需要提供intercept_scaling。
    class_weight : 一个字典或者字符串‘balanced’。
         字典 : 字典给出每个分类的权重。
        balanced : 每个分类的权重与该分类在样本集中出现的频率成反比。
    未指定 : 每个分类权重都为1。
    max_iter : 一个整数,制定最大迭代数。
    random_state :一个整数或者一个RandomState实例,或者None。
    整数,则指定了随机数生成器的种子。
        RandomState,则指定了随机数生成器。
        None,则默认使用随机数生成器。
    solver : 一个字符串,指定了求解最优化的算法,可以为:
        newton-cg : 使用牛顿法。只适用于penalty=‘l2’。
        lbfgs : 使用L-BFGS拟牛顿法。只适用于penalty=‘l2’。
        liblinear : 使用liblinear,适用于小数据集。
        sag : 使用Stochastic Average Gradient Descent算法,适用于大数据集。只适用于penalty=‘l2’。
    tol : 一个浮点数,指定判断迭代收敛与否的阈值
    multi_class : 一个字符串,指定对于多分类问题的策略,可以为:
        ovr : 采用one-vs-rest策略。
        multinomial : 直接采用多分类逻辑回归策略,不能与liblinear共存。
    verbose : 一个正数。用于开启关闭迭代中输出日志。
    warm_start: 一个布尔值。如果为True,那么使用前一次训练结果继续训练。否则从头开始训练
    n_jobs : 一个正数。任务并行时指定的CPU数量。如果为-1则使用所有可用的CPU。
    返回类型
    coef_ : 权重向量。
    intercept_ :b值。
    n_iter :实际迭代次数。

    2.线性模型的图形表示——拟合三点

     再增加一个点(3, 3)再看结果

    #求解穿过点的直线方程,并绘图
    import numpy as np
    import matplotlib.pyplot as plt
    from sklearn.linear_model import LinearRegression #导入线性回归模型
    #输入两点的横坐标
    #X = [[1], [4]]
    #输入两点的纵坐标
    #y = [3, 5]
    
    #输入三点的横坐标
    X = [[1], [4], [3]]
    #输入三点的纵坐标
    y = [3, 5, 3]
    
    #用线性模型拟合输入点
    lr = LinearRegression().fit(X, y)
    
    #画出点和直线图形
    z = np.linspace(0, 5, 20)
    plt.scatter(X, y, s=80)
    plt.plot(z, lr.predict(z.reshape(-1, 1)), c='k')
    #设定图片标题
    plt.title('Straight Line')
    
    #输出直线方程
    print('直线方程为:')
    print('==========================')
    print('y = {:.3f}'.format(lr.coef_[0]), 'x',' + {:.3f}'.format(lr.intercept_))
    plt.show()
    

    执行结果如下,直线未穿过三个点,但是位于一个和3个点距离相加最小的位置:

    直线方程为:
    ==========================
    y = 0.571 x  + 2.143
    
    4.1line_equation_1.png

    3.线性模型的图形表示——拟合多点

     使用scikit-learn 生成的 make_regression 数据集

    #求解穿过多点的直线方程,并绘图
    import numpy as np
    import matplotlib.pyplot as plt
    from sklearn.datasets import make_regression #回归分析数据生成器
    from sklearn.linear_model import LinearRegression #导入线性回归模型
    
    #生成用于回归分析的数据集
    X, y = make_regression(n_samples=50, n_features=1, n_informative=1, noise=50, random_state=1)
    
    #使用线性模型对数据进行拟合
    reg = LinearRegression()
    reg.fit(X, y)
    
    #z是生成的等差数列,用来画出模型的预测结果图形
    z = np.linspace(-3, 3, 200).reshape(-1, 1)
    plt.scatter(X, y, c='b', s=60)
    plt.plot(z, reg.predict(z), c='k')
    
    print('直线方程为:')
    print('==========================')
    print('y = {:.3f}'.format(reg.coef_[0]), 'x',' + {:.3f}'.format(reg.intercept_))
    print('直线的斜率为:{:.2f}'.format(reg.coef_[0]))
    print('直线的截距为:{:.2f}'.format(reg.intercept_))
    
    plt.show()
    

    执行结果如下:

    直线方程为:
    ==========================
    y = 79.525 x  + 10.922
    直线的斜率为:79.52
    直线的截距为:10.92
    
    4.1line_equation_2.png

    注释:

    sklearn.datasets.make_regression

    函数原型:sklearn.datasets.make_regression(_samples=100, n_features=100, n_informative=10,
    n_targets=1, bias=0.0, effective_rank=None,
    tail_strength=0.5, noise=0.0, shuffle=True, coef=False,
    random_state=None)

    关键参数解释
     n_samples(生成样本数)
     n_features(样本特征数)
     noise(样本随机噪音)
     coef(是否返回回归系数)

    返回类型
     X为样本特征
     y为样本输出
     coef为回归系数

    二、基本的线性模型——线性回归

     线性回归,也称为最小二乘法(OLS)。基于预测值很真实值的均方误差最小化来进行模型求解的方法称为“最小二乘法”。在线性回归中,最小二乘法就是试图找到一条直线,使所有样本到直线上的欧式距离之和最小。线性回归没有可供用户调节的参数。这意味着,模型的复杂度不可控。
     使用糖尿病数据集进行演示.

    #线性回归
    #线性回归
    from sklearn.datasets import load_diabetes #载入糖尿病数据
    from sklearn.linear_model import LinearRegression #导入线性回归模型
    from sklearn.model_selection import train_test_split #切分训练集和测试集
    
    X, y = load_diabetes().data, load_diabetes().target
    X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=8)
    
    lr = LinearRegression().fit(X_train, y_train)
    
    print('代码运行结果为:')
    print('==========================')
    print('lr.coef_为:{}'.format(lr.coef_))
    print('lr.intercept_为:{}'.format(lr.intercept_))
    print('\n')
    print('回归方程为:')
    print('==========================')
    print('y = {:.3f}'.format(lr.coef_[0]), '*x1 + {:.3f}'.format(lr.coef_[1]), '*x2' ,' + ({})'.format(lr.intercept_))
    print('\n')
    print('==========================')
    print("训练数据得分:{:.2f}".format(lr.score(X_train, y_train)))
    print("测试数据得分:{:.2f}".format(lr.score(X_test, y_test)))
    

    执行结果如下:

    代码运行结果为:
    ==========================
    lr.coef_为:[   11.5106203   -282.51347161   534.20455671   401.73142674 -1043.89718398
       634.92464089   186.43262636   204.93373199   762.47149733    91.9460394 ]
    lr.intercept_为:152.5624877455247
    
    回归方程为:
    ==========================
    y = 11.511 *x1 + -282.513 *x2  + (152.5624877455247)
    ==========================
    训练数据得分:0.53
    测试数据得分:0.46
    

    结果显示得分很低,也就是模型在实际数据中效果不好,出现了过拟合现象,因此,需要对线性回归模型就行正则化,使得可以控制模型的复杂度。

    2.1、使用L2正则化的线性模型——岭回归

     岭回归是一种改良的最小二乘法。可以避免过拟合。在岭回归中,模型会保留所有的特征变量,但是会减小特征变量的系数值,让特征变量对预测结果的影响变小,在岭回归中是通过改变其alpha参数来控制减小特征变量系数的程度。而这种通过保留全部特征变量,只是降低特征变量的系数值来避免过拟合的方法,成为L2正则化
     在岭回归中。是通过linear_model.Ridge函数来调用的。以糖尿病为例,并对比不同alpha值和线性回归模型下,模型的coef_属性值。

    from sklearn.linear_model import Ridge #导入岭回归
    from sklearn.linear_model import LinearRegression #导入线性回归模型
    from sklearn.datasets import load_diabetes #载入糖尿病数据
    from sklearn.model_selection import train_test_split #切分训练集和测试集
    import matplotlib.pyplot as plt
    
    X, y = load_diabetes().data, load_diabetes().target
    X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=8)
    
    lr = LinearRegression().fit(X_train, y_train)
    
    #取不同的 alpha 来看参数对结果的影响
    ridge1 = Ridge(alpha=1).fit(X_train, y_train)
    ridge10 = Ridge(alpha=10).fit(X_train, y_train)
    ridge01 = Ridge(alpha=0.1).fit(X_train, y_train)
    
    print('代码运行结果为:')
    print('==========================')
    print("训练数据得分:{:.2f}".format(ridge10.score(X_train, y_train)))
    print("测试数据得分:{:.2f}".format(ridge10.score(X_test, y_test)))
    
    #绘制 线性模型系数
    plt.plot(lr.coef_, 'o', label = 'LinearRegression')
    #绘制 alpha = 0.1 时的模型系数
    plt.plot(ridge01.coef_, 's', label = 'Ridge alpha=0.1')
    #绘制 alpha = 1 时的模型系数
    plt.plot(ridge1.coef_, '^', label = 'Ridge alpha=1')
    #绘制 alpha = 10 时的模型系数
    plt.plot(ridge10.coef_, 'v', label = 'Ridge alpha=10')
    plt.xlabel("coefficient index 系数序号")
    plt.ylabel("coeffient magniutde 系数量级")
    plt.hlines(0, 0, len(lr.coef_))
    plt.legend()
    plt.show()
    

    运行结果为:


    4.3Ridge_model.png

    图中。横轴为coef_属性,纵轴为特征变量的系数量级。从图中可以看出,当 alpha = 10 时,特征变量系数大多在0附近;当 alpha = 1时,岭回归的特征变量系数明显增大;;当 alpha = 0.1 时,岭回归的特征变量系数更大,甚至于线性回归模型的点重合了。
     另外一个理解正则化对模型的影响的方法,就取一个固定的alpha值,然后改变训练集的数据量,得到一个随数据集大小而不断改变的模型评分折线图,具体代码如下:

    import numpy as np
    from sklearn.linear_model import Ridge #导入岭回归
    from sklearn.linear_model import LinearRegression #导入线性回归模型
    from sklearn.datasets import load_diabetes #载入糖尿病数据
    from sklearn.model_selection import train_test_split #切分训练集和测试集
    from sklearn.model_selection import learning_curve,KFold
    import matplotlib.pyplot as plt
    
    X, y = load_diabetes().data, load_diabetes().target
    
    #定义一个绘制折线图的函数
    def plot_learning_curve(est, X, y):
        training_set_size, train_scores, test_scores = learning_curve(est, X, y, train_sizes=np.linspace(.1, 1, 20),
                                                                      cv=KFold(20, shuffle=True, random_state=1))
        estimator_name = est.__class__.__name__
        line = plt.plot(training_set_size, train_scores.mean(axis=1), '--', label="training "+ estimator_name)
        plt.plot(training_set_size, test_scores.mean(axis=1), '--', label="test "+ estimator_name, c=line[0].get_color())
        plt.xlabel('Trainint set size')
        plt.ylabel('Score')
        plt.ylim(0, 1.1)
    
    plot_learning_curve(Ridge(alpha=1), X, y)
    plot_learning_curve(LinearRegression(), X, y)
    plt.legend(loc=(0, 1.05), ncol=2, fontsize=11)
    plt.show()
    

    执行结果如下:


    4.4Ridge_model_curves.png

     从图上可以看出,由于岭回归模型是进过正则化的模型,因此它在整个图像中训练数据及的得分比线性回归的低,但是岭回归的测试数据集得分和训练数据集得分差异小。随着数据集的增加,如果有足够多的数据,那么正则化就没那么重要了,岭回归和线性回归的表现相差无几。

    注释1:

    sklearn.model_selection.learning_curve

    函数原型:sklearn.model_selection.learning_curve(estimator, X, y, groups=None, train_sizes=array([0.1, 0.33, 0.55, 0.78, 1. ]), cv=’warn’, scoring=None, exploit_incremental_learning=False, n_jobs=None, pre_dispatch=’all’, verbose=0, shuffle=False, random_state=None, error_score=’raise-deprecating’)

    关键参数解释
    estimator:实现“ fit”和“ predict”方法的对象类型。每次验证都会克隆的该类型的对象。
    X:数组类,形状(n_samples,n_features)。训练向量,其中n_samples是样本数,n_​​features是特征数。
    y:数组类,形状(n_samples)或(n_samples,n_features),可选。相对于X的目标进行分类或回归;无监督学习无。
    groups:数组类,形状为(n_samples,),可选。将数据集拆分为训练/测试集时使用的样本的标签分组。仅用于连接交叉验证实例组(例如GroupKFold)。
    train_sizes:数组类,形状(n_ticks),dtype float或int。训练示例的相对或绝对数量,将用于生成学习曲线。如果dtype为float,则视为训练集最大尺寸的一部分(由所选的验证方法确定),即,它必须在(0,1]之内,否则将被解释为绝对大小注意,为了进行分类,样本的数量通常必须足够大,以包含每个类中的至少一个样本(默认值:np.linspace(0.1,1.0,5))
    cv:int,交叉验证生成器或可迭代的,可选的.确定交叉验证拆分策略。cv的可能输入是:
       None,要使用默认的三折交叉验证(v0.22版本中将改为五折)
       整数,用于指定(分层)KFold中的折叠数,
       CV splitter
       可迭代的集(训练,测试)拆分为索引数组。
       对于整数/无输入,如果估计器是分类器,y是二进制或多类,则使用StratifiedKFold。在所有其他情况下,都使用KFold。
    scoring:字符串,可调用或无,可选,默认:None。字符串(参阅model evaluation documentation)或带有签名scorer(estimator, X, y)的计分器可调用对象/函数。
    exploit_incremental_learning:布尔值,可选,默认值:False. 如果估算器支持增量学习,此参数将用于加快拟合不同训练集大小的速度。
    n_jobs:int或None,可选(默认=None)。要并行运行的作业数。None表示1。 -1表示使用所有处理器。有关更多详细信息,请参见词汇表。
    pre_dispatch:整数或字符串,可选。并行执行的预调度作业数(默认为全部)。该选项可以减少分配的内存。该字符串可以是“ 2 * n_jobs”之类的表达式。
    verbose:整数,可选。控制详细程度:越高,消息越多。
    shuffle:布尔值,可选。是否在基于``train_sizes’'为前缀之前对训练数据进行洗牌。
    random_state:int,RandomState实例或无,可选(默认=None)。如果为int,则random_state是随机数生成器使用的种子;否则为false。如果是RandomState实例,则random_state是随机数生成器;如果为None,则随机数生成器是np.random使用的RandomState实例。在shuffle为True时使用。
    error_score:‘raise’ | ‘raise-deprecating’ 或数字。如果估算器拟合中出现错误,则分配给分数的值。如果设置为“ raise”,则会引发错误。如果设置为“raise-deprecating”,则会在出现错误之前打印FutureWarning。如果给出数值,则引发FitFailedWarning。此参数不会影响重新安装步骤,这将始终引发错误。默认值为“不赞成使用”,但从0.22版开始,它将更改为np.nan。

    返回类型
    train_sizes_abs:数组,形状(n_unique_ticks,),dtype int。已用于生成学习曲线的训练示例数。 请注意,ticks的数量可能少于n_ticks,因为重复的条目将被删除。
    train_scores:数组,形状(n_ticks,n_cv_folds)。训练集得分。
    test_scores:数组,形状(n_ticks,n_cv_folds)。测试集得分。
    函数参考:sklearn中的学习曲线learning_curve函数

    注释2:

    sklearn.model_selection.KFold

    函数原型:KFold(n_split, shuffle, random_state)
    关键参数解释
    n_split:要划分的折数
    shuffle::每次都进行shuffle,测试集中折数的总和就是训练集的个数
    random_state:随机状态

    2.2、使用L1正则化的线性模型——套索回归

     和岭回归一样,套索回归也会 将系数限制在非常接近0 的范围内,但它限制的方式称之为 L1 正则化。与L2 正则化不同的是,L1 正则化会导致在使用套索回归的时候,有一部分特征的系数会正好等于0。也就是说,有一些特征会被模型忽略掉。下面再用糖尿病数据验证套索回归。

    import numpy as np
    from sklearn.linear_model import Ridge #导入套索回归
    from sklearn.linear_model import Lasso #导入岭回归
    from sklearn.datasets import load_diabetes #载入糖尿病数据
    from sklearn.model_selection import train_test_split #切分训练集和测试集
    import matplotlib.pyplot as plt
    
    
    X, y = load_diabetes().data, load_diabetes().target
    X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=8)
    
    #取不同的 alpha 来看参数对套索回归的影响
    lasso01= Lasso(alpha=0.1, max_iter=100000).fit(X_train, y_train)#max_iter迭代次数
    lasso1= Lasso(alpha=1, max_iter=100000).fit(X_train, y_train)
    lasso00001= Lasso(alpha=0.0001, max_iter=100000).fit(X_train, y_train)
    
    #取不同的 alpha 来看参数对岭回归的影响
    ridge01 = Ridge(alpha=0.1).fit(X_train, y_train)
    
    #绘制 alpha =1 时的模型系数
    plt.plot(lasso1.coef_, 's', label = "Lasso alpha=1")
    #绘制 alpha =0.1 时的模型系数
    plt.plot(lasso01.coef_, '^', label = "Lasso alpha=0.1")
    #绘制 alpha =0.00001 时的模型系数
    plt.plot(lasso00001.coef_, 'v', label = "Lasso alpha=0.00001")
    #绘制 alpha =0.1 时的模型系数
    plt.plot(ridge01.coef_, 'o', label = "Ridge alpha=0.1")
    
    plt.legend(loc=(0, 1.05), ncol=2)
    plt.xlabel("Coefficient index")
    plt.ylabel("Coefficient magnitude")
    plt.show()
    

    执行结果如下图,在alpha=1的时候,不仅大部分系数为0,仅存的几个非零系数也特别小。在alpha=0.1的时候,虽然大部分系数为0,但仅存的几个非零系数比alpha=1的时候的大。在alpha=0.0001的时候,模型几乎没有被正则化。


    4.5Lasso_model.png

    2.3、L1正则化和L2正则化的对比

     在实际应用中,岭回归是两个模型中的优选。但要依据实际情况而定。
     数据集中的特征过多,而其中只有一小部分是真正重要的,选L1正则化的模型,如套索回归。
     数据集中的特征本来就不多,而且每一个都有重要的作用,选L2正则化的模型,如岭回归。

    三、其他线性模型

    弹性网模型(Elastic Net):综合了套索回归和岭回归的惩罚因子。实践中,这两个模型的组合效果是组好的,但需要调节2个参数,即L1正则化参数和L2正则化参数。
    逻辑斯蒂回归(Logis Regression)
    线性支持向量机(Linear SVM)

    相关文章

      网友评论

        本文标题:Python机器学习之线性模型

        本文链接:https://www.haomeiwen.com/subject/ynyvektx.html