zoukankan      html  css  js  c++  java
  • 机器学习【二】广义线性模型

    广义线性模型 ——  一预测模型【不是一个】

    使用输入数据集的特征的线性函数进行建模,并对结果进行预测的方法

    线性模型的训练非常快

    过程也很容易被人理解

    但,当数据集的特征比较少的时候,线性模型的表现就会相对偏弱

    一般公式

    也就是,模型给出的预测可以看作是输入特征的加权和,而w就代表了每个特征的权值【可以是负数】

    读作“ y hat ”  ,代表y的估计值

    用Jupyter Notebook 画出直线 y=0.5x+3

    import numpy as np
    import matplotlib.pyplot as plt
    #令x为-5,5之间,元素数为100的等差数列
    x = np.linspace(-5,5,100)
    #输入直线方程
    y = 0.5*x+3
    plt.plot(x,y,c='orange')
    plt.title('Straight Line')
    plt.show()

    如上,线性模型正是通过训练数据集确定自身的系数【斜率】和截距的

    线性模型的图形表示

     1.由(1,3),(4,5)两点画直线

    #导入线性回归模型
    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')
    plt.show()

    确定该直线方程:

    print('斜率:',lr.coef_[0])
    print('截距:',lr.intercept_)

      斜率: 0.6666666666666664
       截距: 2.333333333333334

    2.新加(3,3)点,画直线:

    #导入线性回归模型
    from sklearn.linear_model import LinearRegression
    #输入二点横坐标
    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')
    plt.show()

    print('斜率:',lr.coef_[0])

    print('截距:',lr.intercept_)

    斜率: 0.5714285714285713
    截距: 2.1428571428571432

     线性回归模型的原理:

    让自己距离 每个数据点的 加和为最小值

    3.利用sklearn生成的make_regression数据集为例:

    from sklearn.datasets import make_regression
    #生成用于回归分析的数据集
    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')
    plt.title('Linear Regression')
    plt.show()

    print('斜率:',reg.coef_[0])
    print('截距:',reg.intercept_)

     

    如上,该直线距离50个数据点的距离之和是最小的

     可能注意到 coef_ 和 intercept_ 这两个属性以 '_' 结尾

    这是sklearn的一个特点,总是用下划线作为来自训练数据集的属性的结尾

    以便将它们与由用户设置的参数区分开

     线性模型特点

     以上使用的都是特征数只有1个的数据集

    用于回归分析的线性模型在特征数为1的数据集章,使用一条直线作预测分析

    特征数为2时,是一个平面

    更多——> 高纬度的超平面

    线性模型的预测方法局限——> 很多数据没有体现到这条直线上,因为使用线性模型的前提条件,是假设目标y是数据特征的线性组合

    对于特征变量较多的数据集,线性模型会十分强大【尤其是训练集的特征变量 > 数据点的数量时,可以达到近乎完美的预测】

    用于回归分析的线性模型有好几类,区别:

    如何从训练集中确定参数w,b,如何控制模型的复杂度

    最基本的线性模型——线性回归

    线性回归,也称普通最小二乘法OLS

    1.线性回归的基本原理:

    找到当训练集中y的预测值和其真实值平方差最小的时候所对应的w值 b值

    线性回归没有可供用户调节的参数【优势,但也意味着无法控制模型的复杂性】

    #使用make_regression函数,生成一个样本数量为100,特征数量为2的数据集,并利用 train_test_split 函数将数据集分割成训练集和测试集,再用线性回归模型计算出w、b值

    #导入数据集拆分工具
    from sklearn.model_selection import train_test_split
    from sklearn.linear_model import LinearRegression
    X,y = make_regression(n_samples=100,n_features=2,n_informative=2,random_state=38)
    X_train,X_test,y_train,y_test = train_test_split(X,y,random_state=8)
    lr = LinearRegression().fit(X_train,y_train)
    print('斜率w:',lr.coef_[:])
    print('截距b:',lr.intercept_)

    intercept_ 属性一直是是一个浮点数,而coef_ 属性则是一个Numpy的数组【其中每个特征对应数据中的一个数值】

    #由于使用的make_regression 生成的数据集中数据点有2个特征,所以lr.coef_ 是一个二维数组

    所以,本例中,线性回归方程可以表示为:

    y = 73.3859 * X1 + 7.4321 * X2 - 1.42e-14

     2.线性回归的性能表现

    print(lr.score(X_train,y_train))
    print(lr.score(X_test,y_test))

    1.0
    1.0

     没有向数据集中加入noise,自然满分

    3.真实的数据集:【特征多,noise多】

    from sklearn.datasets import load_diabetes
    #载入糖尿病数据集
    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(lr.score(X_train,y_train))
    print(lr.score(X_test,y_test))

    0.5303814759709331
    0.45934404966916426

     #在训练集和测试集上得分的巨大差异——> 出现过拟合问题,所以应该找到一个模型,是我们能够控制模型的复杂度——> 岭回归

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

    【实际上,是一种改良的最小二乘法】

    【一种能够避免过拟合的线性模型】

    1.原理

    #岭回归在sklearn中通过linear_model.Ridge 函数来调用

    #导入岭回归
    from sklearn.linear_model import Ridge
    #使用岭回归对数据拟合
    rd = Ridge().fit(X_train,y_train)
    #得分
    print(rd.score(X_train,y_train))
    print(rd.score(X_test,y_test))

    0.4326376676137663
    0.43252177690681864

    #复杂度越低的模型。在训练集上表现的越差,但是其泛化的能力更好,如果我们在意的是模型在泛化上的表现,就应该选择岭回归

    2.参数调节 

     【岭回归是在模型的简单性(使系数趋近于0)和它在训练集上的性能之间取得平衡的一种模型】

    可以使用alpha参数控制模型的更加简单性还是性能更好

    【上方例子使用默认参数alpha = 1】

     

     #导入岭回归
    from sklearn.linear_model import Ridge
    #使用岭回归对数据拟合,修改alpha参数为10
    rd10 = Ridge(alpha=10).fit(X_train,y_train)
    #得分
    print(rd10.score(X_train,y_train))
    print(rd10.score(X_test,y_test))

    0.15119962367011153
    0.16202013428866247

     #测试得分>训练得分,说明如果我们的模型出现了过拟合现象,可以提高alpha的值来降低过拟合的程度

    如果降低 alpha 的值,会让系数的限制不严格,如果使用非常小的值,系统的限制可以忽略不计,结果会非常接近线性回归

     

    #导入岭回归
    from sklearn.linear_model import Ridge
    #使用岭回归对数据拟合,修改alpha参数为0.1
    rd1 = Ridge(alpha=0.1).fit(X_train,y_train)
    #得分
    print(rd1.score(X_train,y_train))
    print(rd1.score(X_test,y_test))

    0.5215646055241339
    0.4734019500945309

    【可以尝试降低alpha的值,改善模型的泛化表现 { 测试得分增大 } 】

    为了清晰看出 alpha 值对模型的影响,可以观察 alpha 参数对应的模型的 coef_ 参数:

    【较高的 alpha 代表模型的限制更严格,所以高 alpha 下,coef_数值更大】

     #导入岭回归
    from sklearn.linear_model import Ridge
    #使用岭回归对数据拟合
    rd = Ridge(alpha=1).fit(X_train,y_train)
    rd10 = Ridge(alpha=10).fit(X_train,y_train)
    rd0 = Ridge(alpha=0.1).fit(X_train,y_train)
    #绘制alpha=1时的模型参数
    plt.plot(rd.coef_, 's',label='Ridge alpha=1')
    plt.plot(rd10.coef_, '^',label='Ridge alpha=10')
    plt.plot(rd0.coef_, 'v',label='Ridge alpha=0.1')
    #绘制线性回归的系数作对比
    plt.plot(lr.coef_, 'o',label='linear regression')
    plt.xlabel('coefficient index')
    plt.ylabel('coefficient magitude')
    plt.hlines(0,0,len(lr.coef_))
    plt.legend()

    横轴代表的是 coef_ 属性:

    X=0 显示第一个特征变量系数,X=1显示的是第二个特征变量的系数 。。。。。

    当alpha=10时,特征变量系数大多0附近

    当alpha=1时,岭模型的特征变量系数增大

    alpha=0.1时,系数更大,甚至大部分与线性回归的点重合

     而线性模型没经过任何正则处理,所以特征变量系数会非常大

     另一个理解正则化对模型影响的方法——取一个固定的alpha,改变训练集的数据量

    from sklearn.model_selection import learning_curve,KFold
    #定制一个学习曲线的函数
    def plot_learning_curve(est,X,y):
    #将数据进行20次拆分用来对模型进行评分
        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, train_scores.mean(axis=1),'-',label='test' + estimator_name,c=line[0].get_color())
        plt.xlabel('Training 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)

    得下图,是一个随数据集大小而不断改变的模型评分折线图

    其中的折线,称之为“学习曲线”

    【书上的总共会出现4条曲线,但代码一样,原因未知,所以选取书上例图】

    结论:

    1.无论岭回归还是线性回归,训练集>测试集

    2.岭回归是经过正则化的模型,所以,整个图像中,训练集要比线性回归的低

    3.岭回归在 训练集 和 测试集 的得分差异低【尤其在数据子集比较小的情况】

    4.数据量小于50,线性回归几乎让机器学不到任何东西

    5.随着数据规模增大,线性回归的得分赶上了岭回归的得分——>【足够多的数据,正则化显得不重要,两模型表现差不多】

    #随着数据量的增大,线性回归在训练集的得分下降——> 随着数据增加,线性模型越不容易产生过拟合现象 【即越难记住数据】

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

    1.原理

    同岭回归,也会将系数限制在非常接近0的范围内,但方法不同:有一部分特征的系数正好等于0

    即,一部分特征会被模型忽略掉

    from sklearn.linear_model import Lasso
    #使用套索回归拟合数据
    lasso = Lasso().fit(X_train,y_train)
    #得分
    print(lasso.score(X_train,y_train))
    print(lasso.score(X_test,y_test))

    print(np.sum(lasso.coef_ != 0))  #使用的特征数

    0.36242428249291325
    0.36561858962128
    3

    结果显示出模型发生了欠拟合的问题,在10个特征里套索回归之用了3个

    与岭回归类似。套索回归也有一个正则化参数 alpha,用来控制 特征变量系数被约束到0的强度

    2.参数调节

     降低alpha的值 ——> 降低欠拟合的程度【同时还需要增大最大迭代次数】

    #增大模型迭代次数的默认设置
    #否则模型会提示我们增加最大迭代次数
    lasso01 = Lasso(alpha=0.1,max_iter=100000).fit(X_train,y_train)
    #得分 & 特征数
    print(lasso01.score(X_train,y_train))
    print(lasso01.score(X_test,y_test))
    print(np.sum(lasso01.coef_ != 0))

    0.519480608218357
    0.47994757514558173
    7

    结果:

    降低alpha 值可以拟合出更复杂的模型,从而在训练集和测试集都能获得良好表现

    相对岭回归,套索回归表现稍好,且10个特征只用了7个,使模型更容易被理解

    如果alpha 太低,等于把正则化的效果去除,可能出现过拟合

    #把alpha 设置为0.0001
    lasso000= Lasso(alpha=0.0001,max_iter=100000).fit(X_train,y_train)
    #得分 & 特征数
    print(lasso000.score(X_train,y_train))
    print(lasso000.score(X_test,y_test))
    print(np.sum(lasso000.coef_ != 0))

    0.5303811330981303
    0.4594509683706017
    10

    #使用全部的特征,而且测试集得分略低于alpha=0.1的情况——> 降低alpha 倾向让模型出现过拟合现象

    套索回归和岭回归的区别

     比较不同alpha 值的套索回归和岭回归进行系数对比:

    #绘制alpha 值等于1时的模型系数
    plt.plot(lasso.coef_ ,'s',label='Lasso alpha=1')
    #绘制alpha 值等于0.1时的模型系数
    plt.plot(lasso01.coef_, '^',label='Lasso alpha=0.1')
    #绘制alpha 值等于0.001时的模型系数
    plt.plot(lasso000.coef_, 'v',label='Lasso alpha=0.0001')
    #绘制alpha=0.1 的岭回归模型系数作为对比
    plt.plot(ridge01.coef_,'o',label='Ridge alpha=0.1')
    plt.legend(ncol=2,loc=(0,1.05))
    plt.ylim(-1000,800)
    plt.xlabel('Coefficient index')
    plt.ylabel('Coefficient magnitude')

     

     

    
    
  • 相关阅读:
    mybatis批量更新报错
    Axure8破解码
    小程序开发-Step1
    2018新年计划
    java 写 Excel(不生成实体文件,写为流的形式)
    git 生成公钥 使用命令行无需输入用户名密码(windows)
    Node.js:上传文件,服务端如何获取文件上传进度
    Express:模板引擎深入研究
    windows下nginx的安装及使用
    Chrome开发者工具详解-Network面板
  • 原文地址:https://www.cnblogs.com/expedition/p/10711802.html
Copyright © 2011-2022 走看看