机器学习第六周 机器学习重要概念补充
一、学习目标
- sklearn中的Pipeline
- 偏差与方差
- 模型正则化之L1正则、L2正则
二、学习内容
三、开动ing
前面已经对简单线性回归和多元线性回归做了学习,如果数据没有线性关系那该如何处理。也就是对非线性数据如何处理。
1。多项式回归
在数学中学习过多项式函数,类比线性回归,是否是有多项式回归。
多项式回归:一个因变量与一个或多个自变量多项式的回归分析方法。
如何使用多元线性回归方法解决非线性关系的拟合问题。
比
较
y
1
=
a
x
2
+
b
x
+
c
,
y
2
=
a
x
2
+
b
x
1
+
c
x
0
此
处
x
0
=
1
比较 y_1 = ax^2+bx+c , y_2=ax_2+bx_1+cx_0 此处x_0=1
比较y1=ax2+bx+c,y2=ax2+bx1+cx0此处x0=1
y2为我们多元线性回归的例子,而y_1则是一元多项式的形式,通过比较是否可以将x**2 ,利用x2替换,使用多元线性回归的方式进行对拟合吗?
#模拟一元二次非线性关系
import numpy as np
import matplotlib.pyplot as plt
x = np.random.uniform(-3, 3, size =100)
X = x.reshape(-1,1)
y = 0.5 + x**2 + x + 2 + np.random.normal(0,1,size=100)
plt.scatter(x, y)
plt.show()
上面用到的两个函数np.random.uniform 和 normal
不在numpy中其实也是有random包,有对应的两个函数,这里仅介绍numpy中的。
#均匀分布 [low,high),获得数值将在上述区间范围内
numpy.random.uniform(low=0.0,high = 1.0,size = None)
size 可以为int 或者ints 的tuple (m,n,k)
在绘图中用到de np.random.uniform(-3,3,100) 即在[-3,3)之间随机产生100个数值
#标准(高斯)分布 或者叫做正态分布
np.random.normal(loc=0.0 ,scale=1.0,size=None)
loc 为均值,scale 为standard deviation 标准差 ,size同上
查询类似知识,可以通过浏览器在输入类似
numpy random normal
可查到对应包下的解释
很明显,上面图再用一条直线表示则其误差会很大,直观上感觉更像是一条抛物线,不过开口朝上。
#这里使用简单线性回归拟合,可以看下结果
from sklearn.linear_model import LinearRegression
lin_reg = LinearRegression()
lin_reg.fit(X,y)
y_predict = lin_reg.predict(X)
plt.scatter(X,y)
plt.plot(x , y_predict , color='r')
plt.show()
很显然,这样并不合适,利用x平方,用一个新变量替代的方式,我们使用多元线性回归在试一下,(前提是做个转换)
x
2
−
−
−
>
x
2
x^2 ---> x_2
x2−−−>x2
#利用多元线性回归拟合非线性数据
x2 = np.hstack([X , X**2])
#这里每一行都扩展为了两个变量
lin_reg2 = LinearRegression()
lin_reg2.fit(x2,y)
y_predict2 = lin_reg2.predict(x2)
plt.scatter(x,y)
#需要拍一下序
#plt.plot(x,y_predict2,color='r')
plt.plot(np.sort(x),y_predict2[np.argsort(x)],color='r')
plt.show()
x本身是大小相间的,对应的预测值也是,如果不排序,绘制出来的图形则是像下面一样:
然后得到拟合的系数:
lin_reg2.coef_ ,lin_reg2.intercept_
#系数对应的顺序 x1 x2 , b0
(array([0.9319179 , 1.00814005]), 2.545243861036757)
y = 1.00814 x 2 + 0.9319179 x + 2.54524 y = 1.00814x^2+0.9319179x+2.54524 y=1.00814x2+0.9319179x+2.54524
这种方式是通过我们手工方式实现的,而在sklearn的preprocessing 中PolynomialFeatures则已经帮我们实现了,将代码换成他的实现方式则是:
#使用sklearn中的多项式回归,调用库preprocessing
from sklearn.preprocessing import PolynomialFeatures
#degree表示使用多少次幂的多项式
poly = PolynomialFeatures(degree=2)
poly.fit(X)
X2 = poly.transform(X)
X2.shape
针对PolynomialFeatures的解释:
Generate polynomial and interaction features 生成多项式项
如degree=2且 [a,b] ===>[1 ,a ,b, ,a平方,ab,b平方]
http://lijiancheng0614.github.io/scikit-learn/modules/generated/sklearn.preprocessing.PolynomialFeatures.html
#将原始数据通过polynomialfeatures生成相应的多项式特征
#多项式数据可能还需要进行特征归一化处理
#将数据送给线性回归
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import StandardScaler
poly_reg = Pipeline([
('poly',PolynomialFeatures(degree=2)),
('std_scale',StandardScaler()),
('line_reg',LinearRegression())
])
poly_reg.fit(X,y)
y_predict = poly_reg.predict(X)
plt.scatter(x,y)
plt.plot(np.sort(x),y_predict[np.argsort(x)],color='r')
plt.show()
#上述结果是一样的
在具体实现中,如上sklearn中的Pipeline其将几个过程封装到了一起,利用参数列表中每一个元素实现对应的操作过程。
(1)将原始数据通过PolynomialFeatures生成相应的多项式特征
(2)多项式数据进行特征归一化
(3)将数据送给线性回归
2。ML/DL重要基础概念:偏差和方差
机器学习中过拟合和欠拟合,从其字面意思即可看出一种是拟合过度,虽然这个数据集的结果比较理想,但是换了数据集可能就不好了。而欠拟合,则是理解没到位。
偏差bias:衡量模型的预测值与实际值之间的偏离关系。如果模型准确度为96%,说明低偏差
方差 variance:训练数据在不同迭代阶段的训练模型中,预测值的变化波动情况(或离散情况)。每个预测值与预测均值差的平方和再求平均数。
在低偏差,高方差,这种情况叫做过拟合。是模型太贴合训练数据,导致其泛化或通用的能力变差,这类情况,在使用测试集时往往准确度明显下降。
模型误差=偏差+方差+噪音误差。随着模型复杂度的增加,方差会逐渐增大,而偏差会逐渐变小。
导致产生误差的原因:
(1)有偏差,可能是假设不对,或者欠拟合。
(2)方差上,一点点数据扰动就会出现较大影响。(模型太复杂)
KNN算法,天生是高方差的算法;线性回归则是高偏差算法
那么如何折中,选择?
因此通过上面两个图:
1.在避免偏差是,需要尽量选择正确的模型,
2.在有了正确模型后,慎重选择数据集大小。数据集大到能对整体有代表性后,在增加量,则不会提升模型。训练数据集太小,是欠拟合;过多则会带来过拟合。模型复杂度太高,方差也会很大
3.选择合适的模型复杂度,但复杂度高的模型对训练数据通常有很好的拟合功能,但也可能会导致过拟合。
处理高方差的手段:
降低模型复杂度
减少数据维度;降噪
增加样本书
使用验证集
一种解决过拟合(高方差)的方法:模型正则化
模型正则化 regularization ,对学习算法的修改,限制参数的大小,减少泛化误差而不是训练误差。
正则化的策略包括:约束和惩罚被设计为编码特定类型的先验只是 偏好简单模型 其他形式
from sklearn.linear_model import LinearRegression
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import PolynomialFeatures
from sklearn.metrics import mean_squared_error
from sklearn.model_selection import train_test_split
lin_reg = LinearRegression()
def PolynomialRegression(degree):
return Pipeline([
('poly',PolynomialFeatures(degree)),
('std_scaler',StandardScaler()),
('lin_reg',lin_reg)
])
np.random.seed(666)
x_train,x_test,y_train,y_test = train_test_split(X,y)
poly30_reg = PolynomialRegression(degree=30)
poly30_reg.fit(x_train,y_train)
y30_predict = poly30_reg.predict(x_test)
mean_squared_error(y_test,y30_predict)
#6.918170737784432
x_plot = np.linspace(-3,3,100).reshape(100,1)
y_plot = poly30_reg.predict(x_plot)
plt.scatter(x,y)
plt.plot(x_plot,y_plot,color='r')
plt.axis([-3,3,0,10])
plt.show()
30次的多项式拟合,结合图形来看,明显的过拟合。这里目标函数为了尽可能去拟合数据,使得曲线变得很陡峭。表现在数学上,其方程系数很大
lin_reg.coef_ ,lin_reg.intercept_
(array([ 8.04195683e+13, -8.78259044e+00, 5.18157783e+01, 8.75716369e+01,
-3.74391918e+03, -1.73640368e+03, 9.16252053e+04, 7.28733805e+04,
-1.19429168e+06, -1.13652427e+06, 9.83824544e+06, 9.42869774e+06,
-5.53328893e+07, -4.89040470e+07, 2.21124073e+08, 1.70419876e+08,
-6.41153489e+08, -4.12584616e+08, 1.36031734e+09, 7.02480418e+08,
-2.10764328e+09, -8.37752038e+08, 2.35331893e+09, 6.84512606e+08,
-1.84055045e+09, -3.64748419e+08, 9.55356489e+08, 1.14091041e+08,
-2.95244060e+08, -1.58782105e+07, 4.10754564e+07]),
5.619906062003203)
如何将这里的系数进行调整?
这里就有L1正则化
L1正则化,是在目标函数中添加L1范数。使用L1正则化的模型叫做LASSO回归。
其思路:原本线性回归问题求解是使其目标最优:
是
使
∑
i
=
1
m
(
y
(
i
)
−
θ
0
−
θ
1
X
1
i
−
θ
2
X
2
i
−
.
.
.
−
θ
n
X
n
i
)
最
小
是使\sum_{i=1}^{m}(y^{(i)}-\theta_0-\theta_1X_1^i-\theta_2X_2^i-...-\theta_nX_n^i)最小
是使i=1∑m(y(i)−θ0−θ1X1i−θ2X2i−...−θnXni)最小
这几就是原始数据y和使用参数后预测值的均方误差尽可能的小
J ( θ ) = M S E ( y , y ^ : θ ) 尽 可 能 小 J(\theta) =MSE(y,\hat{y}:\theta)尽可能小 J(θ)=MSE(y,y^:θ)尽可能小
如果过拟合的话,正如上面,其参数会非常大。
因此提供思路是限制参数,将参数引入目标函数中,引入正则化:
使 J ( θ ) = M S E ( y , y ^ ; θ ) + α ∑ i = 1 n ∣ θ i ∣ 尽 可 能 小 使J(\theta)=MSE(y,\hat{y};\theta)+\alpha\sum_{i=1}^{n}{|\theta_i|}尽可能小 使J(θ)=MSE(y,y^;θ)+αi=1∑n∣θi∣尽可能小
这样要使其J尽可能小,总和两项,后面带系数的参数绝对值和,要是尽可能小,因此就会避免之前看到的问题。
LASSO : least absolute shrinkage and selection operation regression
:
1
,
θ
,
这
里
没
有
计
算
、
θ
0
,
因
为
这
个
是
截
距
,
不
影
响
曲
线
的
陡
峭
与
缓
和
,
只
是
将
曲
线
整
体
平
移
。
:
2
,
α
表
示
优
化
的
侧
重
,
即
后
面
这
一
项
在
整
体
优
化
目
标
函
数
中
权
重
程
度
:1 ,\theta,这里没有计算、\theta_0,因为这个是截距,不影响曲线的陡峭与缓和,只是将曲线整体平移。 :2 ,\alpha 表示优化的侧重,即后面这一项在整体优化目标函数中权重程度
:1,θ,这里没有计算、θ0,因为这个是截距,不影响曲线的陡峭与缓和,只是将曲线整体平移。:2,α表示优化的侧重,即后面这一项在整体优化目标函数中权重程度
L1正则化的影响:
稀疏性:模型中很多参数是0
L1正则化可以使得参数稀疏化。对模型进行了一次特征选择,只留下一些比较重要的特征,提高模型的泛化能力,降低过拟合的可能。(降低模型的复杂度)
def LassoRegression(degree,alpha):
return Pipeline([
('poly',PolynomialFeatures(degree)),
('std_scaler',StandardScaler()),
('lin_reg',Lasso(alpha=alpha))
])
#lasso
lasso_reg = LassoRegression(degree=30, alpha = 0.0001)
lasso_reg.fit(x_train,y_train)
ylasso_predict = lasso_reg.predict(x_test)
mean_squared_error(y_test,ylasso_predict)
#1.2253114093425905
x_plot = np.linspace(-3,3,100).reshape(100,1)
y_plot = poly30_reg.predict(x_plot)
ylasso_plot = lasso_reg.predict(x_plot)
plt.scatter(x,y)
plt.plot(x_plot,y_plot,color='r')
plt.plot(x_plot,ylasso_plot,color='b')
plt.axis([-3,3,0,10])
plt.show()
蓝色的线则是加入了L1正则化后的结果,其方差也有明显变化6.x—>1.x
alpha =0.1时:
alpha 过大时:
因此alpha的值要适中。
一般我们在考虑到绝对值时,很自然会想到平方,这时会有另外一种正则化方式L2正则化
L2正则化
岭回归,:
J
(
θ
)
=
M
S
E
(
y
,
y
^
:
θ
)
+
α
∑
i
=
1
n
θ
2
尽
可
能
的
小
J(\theta) = MSE(y,\hat{y}:\theta) +\alpha \sum_{i=1}^{n}\theta^2尽可能的小
J(θ)=MSE(y,y^:θ)+αi=1∑nθ2尽可能的小
L2范数的结果,是比较平滑,但是不具有稀疏性。
def ridgeRegression(degree, alpha):
return Pipeline([
('poly',PolynomialFeatures(degree)),
('std_scaler',StandardScaler()),
('lin_reg',Ridge(alpha=alpha))
])
#ridge L2范式
ridge_reg = ridgeRegression(degree=30, alpha =0.1)
ridge_reg.fit(x_train, y_train)
yridge_predict = ridge_reg.predict(x_test)
ridge_mse = mean_squared_error(y_test,yridge_predict)
poly30_mse,lasso_mse,ridge_mse
#(6.918170737784432, 1.0131853164117148, 1.2048961054331477)
可以看出L2范式结果的均方误差比过拟合的6.9要好很多。
#上图绘图的代码如下,黄色是L2正则化,蓝色是L1正则化,红色是过拟合
x_plot = np.linspace(-3,3,100).reshape(100,1)
y_plot = poly30_reg.predict(x_plot)
ylasso_plot = lasso_reg.predict(x_plot)
yridge_plot = ridge_reg.predict(x_plot)
plt.scatter(x,y)
plt.plot(x_plot,y_plot,color='r')
plt.plot(x_plot,ylasso_plot,color='b')
plt.plot(x_plot,yridge_plot,color='y')
plt.axis([-3,3,0,10])
plt.show()
L2 alpha =0.0001
alpha = 0.1
alpha =100
从L1和L2相比较,alpha取值过大都会导致误差增加,拟合曲线会变成直线。
LASSO 更倾向于是的部分参数为0,产生参数稀疏,拟合曲线更倾向于直线。所以作为特征选择使用。Lasso可能会去掉正确的特征,从而降低准确度,但如果特征特别大,使用LASSO可使模型变小。
总结:
本文从非线性回归入手,利用多元线性回归实现了非线性回归。接着高次非线性拟合的过拟合问题入手,介绍了两种正则化的解决方案。
注:本文代码参考值: 数据科学家联盟 木东居士 和 饼干
是机器学习小组的学习笔记。