机器学习【二】广义线性模型

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

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

 

线性模型的训练非常快

过程也很容易被人理解

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

 

一般公式

也就是,模型给出的预测可以看作是输入特征的加权和,而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')

 

 

 

 

 

 


posted @ 2019-04-17 15:25  远征i  阅读(181)  评论(0编辑  收藏