均方误差
M S E = 1 N ∑ i = 1 N ( y i − f ^ ( x i ) ) 2 MSE = \frac{1}{N}\sum\limits_{i=1}^{N}(y_i -\hat{ f}(x_i))^2 MSE=N1i=1∑N(yi−f^(xi))2
优化基础模型
一般在训练误差达到最小时,测试均方误差一般很大
偏差与方差的均衡
E ( y 0 − f ^ ( x 0 ) ) 2 = Var ( f ^ ( x 0 ) ) + [ Bias ( f ^ ( x 0 ) ) ] 2 + Var ( ε ) E\left(y_{0}-\hat{f}\left(x_{0}\right)\right)^{2}=\operatorname{Var}\left(\hat{f}\left(x_{0}\right)\right)+\left[\operatorname{Bias}\left(\hat{f}\left(x_{0}\right)\right)\right]^{2}+\operatorname{Var}(\varepsilon) E(y0−f^(x0))2=Var(f^(x0))+[Bias(f^(x0))]2+Var(ε)
测试均方误差的期望值可以分解为 f ^ ( x 0 ) \hat{f}(x_0) f^(x0)的方差、 f ^ ( x 0 ) \hat{f}(x_0) f^(x0)的偏差平方和误差项 ϵ \epsilon ϵ的方差
测试均方误差的期望不可能会低于误差 ϵ \epsilon ϵ的方差,因此称 Var ( ε ) \operatorname{Var}(\varepsilon) Var(ε)为建模任务的难度,这个量在我们的任务确定后是无法改变的,也叫做不可约误差
模型的方差就是:用不同的数据集去估计 f f f时,估计函数的改变量,一般来说,模型的复杂度越高,f的方差就会越大。
模型的偏差是指:为了选择一个简单的模型去估计真实函数所带入的误差。偏差度量了学习算法的期望预测与真实结果的偏离程度,即刻画了学习算法本身的拟合能力
偏差度量的是单个模型的学习能力,而方差度量的是同一个模型在不同数据集上的稳定性
特征提取——对特征自身进行选择
训练误差修正
前面的讨论我们已经知道,模型越复杂,训练误差越小,测试误差先减后增。因此,我们先构造一个特征较多的模型使其过拟合,此时训练误差很小而测试误差很大,那这时我们加入关于特征个数的惩罚。因此,当我们的训练误差随着特征个数的增加而减少时,惩罚项因为特征数量的增加而增大,抑制了训练误差随着特征个数的增加而无休止地减小。具体的数学量如下:
C
p
=
1
N
(
R
S
S
+
2
d
σ
^
2
)
C_p = \frac{1}{N}(RSS + 2d\hat{\sigma}^2)
Cp=N1(RSS+2dσ^2),其中d为模型特征个数,
R
S
S
=
∑
i
=
1
N
(
y
i
−
f
^
(
x
i
)
)
2
RSS = \sum\limits_{i=1}^{N}(y_i-\hat{f}(x_i))^2
RSS=i=1∑N(yi−f^(xi))2,
σ
^
2
\hat{\sigma}^2
σ^2为模型预测误差的方差的估计值,即残差的方差。
AIC赤池信息量准则:
A
I
C
=
1
d
σ
^
2
(
R
S
S
+
2
d
σ
^
2
)
AIC = \frac{1}{d\hat{\sigma}^2}(RSS + 2d\hat{\sigma}^2)
AIC=dσ^21(RSS+2dσ^2)
BIC贝叶斯信息量准则:
B
I
C
=
1
n
(
R
S
S
+
l
o
g
(
n
)
d
σ
^
2
)
BIC = \frac{1}{n}(RSS + log(n)d\hat{\sigma}^2)
BIC=n1(RSS+log(n)dσ^2)
交叉验证
前面讨论的对训练误差修正得到测试误差的估计是间接方法,这种方法的桥梁是训练误差,而交叉验证则是对测试误差的直接估计。交叉验证比训练误差修正的优势在于:能够给出测试误差的一个直接估计。在这里只介绍K折交叉验证:我们把训练样本分成K等分,然后用K-1个样本集当做训练集,剩下的一份样本集为验证集去估计由K-1个样本集得到的模型的精度,这个过程重复K次取平均值得到测试误差的一个估计 C V ( K ) = 1 K ∑ i = 1 K M S E i CV_{(K)} = \frac{1}{K}\sum\limits_{i=1}^{K}MSE_i CV(K)=K1i=1∑KMSEi。5折交叉验证如下图:(蓝色的是训练集,黄色的是验证集)
在测试误差能够被合理的估计出来以后,我们做特征选择的目标就是:从p个特征中选择m个特征,使得对应的模型的测试误差的估计最小。对应的方法有:最优子集选择和向前逐步选择
最优子集选择
(i) 记不含任何特征的模型为 M 0 M_0 M0,计算这个 M 0 M_0 M0的测试误差。
(ii) 在
M
0
M_0
M0基础上增加一个变量,计算p个模型的RSS,选择RSS最小的模型记作
M
1
M_1
M1,并计算该模型
M
1
M_1
M1的测试误差。
(iii) 再增加变量,计算p-1个模型的RSS,并选择RSS最小的模型记作
M
2
M_2
M2,并计算该模型
M
2
M_2
M2的测试误差。 (iv) 重复以上过程直到拟合的模型有p个特征为止,并选择p+1个模型
{
M
0
,
M
1
,
.
.
.
,
M
p
}
\{M_0,M_1,...,M_p \}
{M0,M1,...,Mp}中测试误差最小的模型作为最优模型。
向前逐步选择
最优子集选择虽然在原理上很直观,但是随着数据特征维度p的增加,子集的数量为
2
p
2^p
2p,计算效率非常低下且需要的计算内存也很高,在大数据的背景下显然不适用。因此,我们需要把最优子集选择的运算效率提高,因此向前逐步选择算法的过程如下:
(i) 记不含任何特征的模型为
M
0
M_0
M0,计算这个
M
0
M_0
M0的测试误差。
(ii) 在
M
0
M_0
M0基础上增加一个变量,计算p个模型的RSS,选择RSS最小的模型记作
M
1
M_1
M1,并计算该模型
M
1
M_1
M1的测试误差。
(iii) 在最小的RSS模型下继续增加一个变量,选择RSS最小的模型记作
M
2
M_2
M2,并计算该模型
M
2
M_2
M2的测试误差。 (iv) 以此类推,重复以上过程直到拟合的模型有p个特征为止,并选择p+1个模型
{
M
0
,
M
1
,
.
.
.
,
M
p
}
\{M_0,M_1,...,M_p \}
{M0,M1,...,Mp}中测试误差最小的模型作为最优模型。
压缩估计(正则化)——对系数进行约束
压缩估计——把回归系数往零的方向进行压缩,从而提高模型的拟合效果
岭回归(L2正则化)
在线性回归中,我们的损失函数为
J
(
w
)
=
∑
i
=
1
N
(
y
i
−
w
0
−
∑
j
=
1
p
w
j
x
i
j
)
2
J(w) = \sum\limits_{i=1}^{N}(y_i-w_0-\sum\limits_{j=1}^{p}w_jx_{ij})^2
J(w)=i=1∑N(yi−w0−j=1∑pwjxij)2,我们在线性回归的损失函数的基础上添加对系数的约束或者惩罚,即:
J
(
w
)
=
∑
i
=
1
N
(
y
i
−
w
0
−
∑
j
=
1
p
w
j
x
i
j
)
2
+
λ
∑
j
=
1
p
w
j
2
,
其
中
,
λ
≥
0
w
^
=
(
X
T
X
+
λ
I
)
−
1
X
T
Y
J(w) = \sum\limits_{i=1}^{N}(y_i-w_0-\sum\limits_{j=1}^{p}w_jx_{ij})^2 + \lambda\sum\limits_{j=1}^{p}w_j^2,\;\;其中,\lambda \ge 0\\ \hat{w} = (X^TX + \lambda I)^{-1}X^TY
J(w)=i=1∑N(yi−w0−j=1∑pwjxij)2+λj=1∑pwj2,其中,λ≥0w^=(XTX+λI)−1XTY
调节参数
λ
\lambda
λ的大小是影响压缩估计的关键,
λ
\lambda
λ越大,惩罚的力度越大,系数则越趋近于0,反之,选择合适的
λ
\lambda
λ对模型精度来说十分重要。岭回归通过牺牲线性回归的无偏性降低方差,有可能使得模型整体的测试误差较小,提高模型的泛化能力。
sklearn.linear_model.ridge_regression
- 参数:
alpha:较大的值表示更强的正则化。浮点数
sample_weight:样本权重,默认无。
solver:求解方法,{‘auto’, ‘svd’, ‘cholesky’, ‘lsqr’, ‘sparse_cg’, ‘sag’, ‘saga’}, 默认=’auto’。“ svd”使用X的奇异值分解来计算Ridge系数。'cholesky’使用标准的scipy.linalg.solve函数通过dot(XT,X)的Cholesky分解获得封闭形式的解。'sparse_cg’使用scipy.sparse.linalg.cg中的共轭梯度求解器。作为一种迭代算法,对于大规模数据(可能设置tol和max_iter),此求解器比“ Cholesky”更合适。 lsqr”使用专用的正则化最小二乘例程scipy.sparse.linalg.lsqr。它是最快的,并且使用迭代过程。“ sag”使用随机平均梯度下降,“ saga”使用其改进的无偏版本SAGA。两种方法都使用迭代过程,并且当n_samples和n_features都很大时,通常比其他求解器更快。请注意,只有在比例大致相同的要素上才能确保“ sag”和“ saga”快速收敛。您可以使用sklearn.preprocessing中的缩放器对数据进行预处理。最后五个求解器均支持密集和稀疏数据。但是,当fit_intercept为True时,仅’sag’和’sparse_cg’支持稀疏输入。
Lasso回归(L1正则化)
岭回归的一个很显著的特点是:将模型的系数往零的方向压缩,但是岭回归的系数只能趋于0但无法等于0,换句话说,就是无法做特征选择(系数等于0相当于放弃特征,就是做特征选择)。能否使用压缩估计的思想做到像特征最优子集选择那样提取出重要的特征呢?答案是肯定的!我们只需要对岭回归的优化函数做小小的调整就行了,我们使用系数向量的L1范数替换岭回归中的L2范数:
J
(
w
)
=
∑
i
=
1
N
(
y
i
−
w
0
−
∑
j
=
1
p
w
j
x
i
j
)
2
+
λ
∑
j
=
1
p
∣
w
j
∣
,
其
中
,
λ
≥
0
J(w) = \sum\limits_{i=1}^{N}(y_i-w_0-\sum\limits_{j=1}^{p}w_jx_{ij})^2 + \lambda\sum\limits_{j=1}^{p}|w_j|,\;\;其中,\lambda \ge 0
J(w)=i=1∑N(yi−w0−j=1∑pwjxij)2+λj=1∑p∣wj∣,其中,λ≥0
为什么Losso能做到特征选择而岭回归却不能做到呢?(如图:左边为lasso,右边为岭回归)
椭圆形曲线为RSS等高线,菱形和圆形区域分别代表了L1和L2约束,Lsaao回归和岭回归都是在约束下的回归,因此最优的参数为椭圆形曲线与菱形和圆形区域相切的点。但是Lasso回归的约束在每个坐标轴上都有拐角,因此当RSS曲线与坐标轴相交时恰好回归系数中的某一个为0,这样就实现了特征提取。反观岭回归的约束是一个圆域,没有尖点,因此与RSS曲线相交的地方一般不会出现在坐标轴上,因此无法让某个特征的系数为0,因此无法做到特征提取。
class sklearn.linear_model.Lasso
Lasso(alpha=1.0, fit_intercept=True, normalize=False, precompute=False,
copy_X=True, max_iter=1000, tol=0.0001, warm_start=False,
positive=False, random_state=None, selection=‘cyclic’
)
参数:
- alphas:指定λ值,默认为1,代表标准最小二乘。
- fit_intercept:bool类型,是否需要拟合截距项,默认为True。
- normalize:bool类型,建模时是否对数据集做标准化处理,默认为False。
- precompute:bool类型,是否在建模前计算Gram矩阵提升运算速度,默认为False。
- copy_X:bool类型,是否复制自变量X的数值,默认为True。
- max_iter:指定模型的最大迭代次数。
- tol:指定模型收敛的阈值,默认为0.0001。
- warm_start:bool类型,是否将前一次训练结果用作后一次的训练,默认为False。
- positive:bool类型,是否将回归系数强制为正数,默认为False。
- random_state:指定随机生成器的种子。
- selection:指定每次迭代选择的回归系数,如果为’random’,表示每次迭代中将随机更新回归系数;如果为’cyclic’,则每次迭代时回归系数的更新都基于上一次运算。
降维
将原始的特征空间投影到一个低维的空间实现变量的数量变少,采用某种映射方法,将原高维空间中的数据点映射到低维度的空间中
为什么要降维?
减少冗余信息所造成的误差,提高识别(或其他应用)的精度。又或者希望通过降维算法来寻找数据内部的本质结构特征。
主成分分析(PCA)
主成分分析的思想:通过最大投影方差 将原始空间进行重构,即由特征相关重构为无关,即落在某个方向上的点(投影)的方差最大。在进行下一步推导之前,我们先把样本均值和样本协方差矩阵推广至矩阵形式: 样本均值Mean: x ˉ = 1 N ∑ i = 1 N x i = 1 N X T 1 N , 其 中 1 N = ( 1 , 1 , . . . , 1 ) N T \bar{x} = \frac{1}{N}\sum\limits_{i=1}^{N}x_i = \frac{1}{N}X^T1_N,\;\;\;其中1_N = (1,1,...,1)_{N}^T xˉ=N1i=1∑Nxi=N1XT1N,其中1N=(1,1,...,1)NT
样本协方差矩阵 S 2 = 1 N ∑ i = 1 N ( x i − x ˉ ) ( x i − x ˉ ) T = 1 N X T H X , 其 中 , H = I N − 1 N 1 N 1 N T S^2 = \frac{1}{N}\sum\limits_{i=1}^{N}(x_i-\bar{x})(x_i-\bar{x})^T = \frac{1}{N}X^THX,\;\;\;其中,H = I_N - \frac{1}{N}1_N1_N^T S2=N1i=1∑N(xi−xˉ)(xi−xˉ)T=N1XTHX,其中,H=IN−N11N1NT 最大投影方差的步骤:
(i) 中心化: x i − x ˉ x_i - \bar{x} xi−xˉ
(ii) 计算每个点
x
1
,
.
.
.
,
x
N
x_1,...,x_N
x1,...,xN至
u
⃗
1
\vec{u}_1
u1方向上的投影:
(
x
i
−
x
ˉ
)
u
⃗
1
,
∣
∣
u
⃗
1
∣
∣
=
1
(x_i-\bar{x})\vec{u}_1,\;\;\;||\vec{u}_1|| = 1
(xi−xˉ)u1,∣∣u1∣∣=1
(iii) 计算投影方差:
J
=
1
N
∑
i
=
1
N
[
(
x
i
−
x
ˉ
)
T
u
⃗
1
]
2
,
∣
∣
u
⃗
1
∣
∣
=
1
J = \frac{1}{N}\sum\limits_{i=1}^{N}[(x_i-\bar{x})^T\vec{u}_1]^2,\;\;\;||\vec{u}_1|| = 1
J=N1i=1∑N[(xi−xˉ)Tu1]2,∣∣u1∣∣=1
(iv) 最大化投影方差求
u
⃗
1
\vec{u}_1
u1:
u
ˉ
1
=
a
r
g
m
a
x
u
1
1
N
∑
i
=
1
N
[
(
x
i
−
x
ˉ
)
T
u
⃗
1
]
2
s
.
t
.
u
⃗
1
T
u
⃗
1
=
1
(
u
⃗
1
往
后
不
带
向
量
符
号
)
\bar{u}_1 = argmax_{u_1}\;\;\frac{1}{N}\sum\limits_{i=1}^{N}[(x_i-\bar{x})^T\vec{u}_1]^2 \\ \;\;\;s.t. \vec{u}_1^T\vec{u}_1 = 1 (\vec{u}_1往后不带向量符号)
uˉ1=argmaxu1N1i=1∑N[(xi−xˉ)Tu1]2s.t.u1Tu1=1(u1往后不带向量符号)
得到:
J
=
1
N
∑
i
=
1
N
[
(
x
i
−
x
ˉ
)
T
u
⃗
1
]
2
=
1
N
∑
i
=
1
N
[
u
1
T
(
x
i
−
x
ˉ
)
(
x
i
−
x
ˉ
)
T
u
1
]
=
u
1
T
[
1
N
∑
i
=
1
N
(
x
i
−
x
ˉ
)
(
x
i
−
x
ˉ
)
T
]
u
1
=
u
1
T
S
2
u
1
J = \frac{1}{N}\sum\limits_{i=1}^{N}[(x_i-\bar{x})^T\vec{u}_1]^2 = \frac{1}{N}\sum\limits_{i=1}^{N}[u_1^T(x_i-\bar{x})(x_i-\bar{x})^Tu_1]\\ \; = u_1^T[\frac{1}{N}\sum\limits_{i=1}^{N}(x_i-\bar{x})(x_i - \bar{x})^T]u_1 = u_1^TS^2u_1
J=N1i=1∑N[(xi−xˉ)Tu1]2=N1i=1∑N[u1T(xi−xˉ)(xi−xˉ)Tu1]=u1T[N1i=1∑N(xi−xˉ)(xi−xˉ)T]u1=u1TS2u1
即:
u
^
1
=
a
r
g
m
a
x
u
1
u
1
T
S
2
u
1
,
s
.
t
.
u
1
T
u
1
=
1
L
(
u
1
,
λ
)
=
u
1
T
S
2
u
1
+
λ
(
1
−
u
1
T
u
1
)
∂
L
∂
u
1
=
2
S
2
u
1
−
2
λ
u
1
=
0
即
:
S
2
u
1
=
λ
u
1
\hat{u}_1 = argmax_{u_1}u_1^TS^2u_1,\;\;\;s.t.u_1^Tu_1 = 1\\ L(u_1,\lambda) = u_1^TS^2u_1 + \lambda (1-u_1^Tu_1)\\ \frac{\partial L}{\partial u_1} = 2S^2u_1-2\lambda u_1 = 0\\ 即:S^2u_1 = \lambda u_1
u^1=argmaxu1u1TS2u1,s.t.u1Tu1=1L(u1,λ)=u1TS2u1+λ(1−u1Tu1)∂u1∂L=2S2u1−2λu1=0即:S2u1=λu1
可以看到:
λ
\lambda
λ为
S
2
S^2
S2的特征值,
u
1
u_1
u1为
S
2
S^2
S2的特征向量。因此我们只需要对中心化后的协方差矩阵进行特征值分解,得到的特征向量即为投影方向。如果需要进行降维,那么只需要取p的前M个特征向量即可。
对超参进行调优
参数和超参数
模型参数是模型内部的配置变量,其值可以根据数据进行估计
- 进行预测时需要参数。
- 它参数定义了可使用的模型。
- 参数是从数据估计或获悉的。
- 参数通常不由编程者手动设置。
- 参数通常被保存为学习模型的一部分。
- 参数是机器学习算法的关键,它们通常由过去的训练数据中总结得出 。
模型超参数是模型外部的配置,其值无法从数据中估计
- 超参数通常用于帮助估计模型参数
- 超参数通常由人工指定
- 超参数通常可以使用启发式设置
- 超参数经常被调整为给定的预测建模问题
网格搜索GridSearchCV()
从超参数空间中寻找最优的超参数——先做超参数组合,分别建立模型,然后选择测试误差最小的那组超参数
随机搜索 RandomizedSearchCV()
参数的随机搜索中的每个参数都是从可能的参数值的分布中采样的
优点:
- 可以独立于参数数量和可能的值来选择计算成本。
- 添加不影响性能的参数不会降低效率
LassoCV()——Lasso回归的超参调优
LassoCV(eps=0.001, n_alphas=100, alphas=None, fit_intercept=True,
normalize=False, precompute=‘auto’, max_iter=1000, tol=0.0001,
copy_X=True, cv=None, verbose=False, n_jobs=1, positive=False,
random_state=None, selection=‘cyclic’)
参数:
- eps:指代λ 最小值与最大值的商,默认为0.001。
- n_alphas:指定λ的个数,默认为100个。
- alphas:指定具体的λ列表用于模型的运算。
- fit_intercept:bool类型,是否需要拟合截距项,默认为True。
- normalize:bool类型,建模时是否对数据集做标准化处理,默认为False。
- precompute:bool类型,是否在建模前计算Gram矩阵提升运算速度,默认为False。
- max_iter:指定模型的最大迭代次数。
- tol:指定模型收敛的阈值,默认为0.0001。
- copy_X:bool类型,是否复制自变量X的数值,默认为True。
- cv:指定交叉验证的重数。
- verbose:bool类型,是否返回模型运行的详细信息,默认为False。
- n_jobs:指定使用的CPU数量,默认为1,如果为-1表示所有CPU用于交叉验证的运算。
- positive:bool类型,是否将回归系数强制为正数,默认为False。
- random_state:指定随机生成器的种子。
- selection:指定每次迭代选择的回归系数,如果为’random’,表示每次迭代中将随机更新回归系数;如果为’cyclic’,则每次迭代时回归系数的更新都基于上一次运算。
作业
1.用一个具体的案例解释偏差和方差
方差描述的是训练数据在不同迭代阶段的训练模型中,预测值的变化波动情况,例如对过输入中国人身高去预测我们的体重,每次抽取1000个样本,抽取1000次,得到1000个模型,这些模型的参数不可能完全一样,这些参数的差异就是方差
偏差描述的是预测值(估计值)的期望与真实值之间的差距,例如真实的身高和体重是线性关系,而当我们使用二次关系模型进行建模时预测的值和真实值的差异就称为偏差
2.偏差与方差误差的关系
E ( y 0 − f ^ ( x 0 ) ) 2 = Var ( f ^ ( x 0 ) ) + [ Bias ( f ^ ( x 0 ) ) ] 2 + Var ( ε ) E\left(y_{0}-\hat{f}\left(x_{0}\right)\right)^{2}=\operatorname{Var}\left(\hat{f}\left(x_{0}\right)\right)+\left[\operatorname{Bias}\left(\hat{f}\left(x_{0}\right)\right)\right]^{2}+\operatorname{Var}(\varepsilon) E(y0−f^(x0))2=Var(f^(x0))+[Bias(f^(x0))]2+Var(ε)
测试均方误差的期望值可以分解为 f ^ ( x 0 ) \hat{f}(x_0) f^(x0)的方差、 f ^ ( x 0 ) \hat{f}(x_0) f^(x0)的偏差平方和误差项 ϵ \epsilon ϵ的方差
3.训练误差和测试误差之间的联系与区别
使用训练集中的数据计算均方误差得到的是训练误差,使用测试集中的数据计算得到的是测试误差,我们通常通过减小训练误差以求得到更好的模型,但同时训练误差过小时并不能满足测试误差也很小,有时会出现过拟合的问题,训练误差很小的情况下测试误差却非常大。
4.使用三种方式进行特征简化并且使用网格搜索调参
特征提取——向前逐步选择
特征简化
import numpy as np
import pandas as pd
# from sklearn.datasets import fetch_california_housing as fch #加载加利福尼亚房屋价值数据
from sklearn import datasets
#加载线性回归需要的模块和库
import statsmodels.api as sm #最小二乘
from statsmodels.formula.api import ols #加载ols模型
# data=fch() #导入数据
data = datasets.load_boston()
house_data=pd.DataFrame(data.data)
house_data.columns=data.feature_names
house_data["value"] = data.target
#分训练集测试集
import random
random.seed(123) #设立随机数种子
a=random.sample(range(len(house_data)),round(len(house_data)*0.3))
#sample函数用于截取列表的指定长度的随机数,但是不会改变列表本身的排序,这里是从所有的20640个样本中随机选择样本作为测试集
#选择的样本的个数为样本总数的30%,round()函数用来四舍五入取整数
#a返回一个列表
house_test=[]
for i in a:#选择测试集
house_test.append(house_data.iloc[i])
house_test=pd.DataFrame(house_test)#转化为pandas格式
house_train = house_data.drop(a)#剩下的作为训练集
#定义向前逐步回归函数
def forward_select(data,target):
variate=set(data.columns) #将字段名转换成字典类型
variate.remove(target) #去掉因变量的字段名
selected=[]
# float("inf")表示正无穷
current_score,best_new_score=float('inf'),float('inf') #目前的分数和最好分数初始值都为无穷大(因为AIC越小越好)
#循环筛选变量
while variate:
aic_with_variate=[]
# 从一个变量开始,计算所有模型的aic值
for candidate in variate: #逐个遍历自变量
formula="{}~{}".format(target,"+".join(selected+[candidate])) #将自变量名连接起来
#https://www.statsmodels.org/stable/generated/statsmodels.formula.api.ols.html#statsmodels.formula.api.ols
# formula的格式是"xxx~xxx+xxx",例如'sales ~ TV + radio'表示电视和收音机对销售额的影响,~前面的是因变量,~后面的是自变量
aic=ols(formula=formula,data=data).fit().aic #利用ols训练模型得出aic值
aic_with_variate.append((aic,candidate)) #将第每一次的aic值放进空列表
aic_with_variate.sort(reverse=True) #降序排序aic值
#找到AIC最小的模型
best_new_score,best_candidate=aic_with_variate.pop() #最好的aic值等于删除列表的最后一个值,以及最好的自变量等于列表最后一个自变量
if current_score>best_new_score: #如果目前的aic值大于最好的aic值
variate.remove(best_candidate) #移除加进来的变量名,即第二次循环时,不考虑此自变量了
selected.append(best_candidate) #将此自变量作为加进模型中的自变量
current_score=best_new_score #最新的分数等于最好的分数
print("aic is {},continuing!".format(current_score)) #输出最小的aic值
else:
print("for selection over!")
break
formula="{}~{}".format(target,"+".join(selected)) #最终的模型式子
set_all = set(list(house_train.columns)[0:-1]) #所有特征
set_selected = set(selected)
set_del = set_all ^ set_selected
print(set_del)
print("final formula is {}".format(formula))
model=ols(formula=formula,data=data).fit()
return model
model = forward_select(data=house_train,target="value")
aic is 2247.322941110846,continuing!
aic is 2169.908731130666,continuing!
aic is 2122.5870959236045,continuing!
aic is 2111.8843470028705,continuing!
aic is 2086.800752486827,continuing!
aic is 2073.5128974973395,continuing!
aic is 2065.473418001696,continuing!
aic is 2061.2817883897087,continuing!
aic is 2058.91624514248,continuing!
aic is 2054.8289103424245,continuing!
aic is 2047.1942858182174,continuing!
for selection over!
{'INDUS', 'AGE'}
final formula is value~LSTAT+RM+PTRATIO+DIS+NOX+CHAS+CRIM+ZN+B+RAD+TAX
model.summary()
Dep. Variable: | value | R-squared: | 0.768 |
---|---|---|---|
Model: | OLS | Adj. R-squared: | 0.761 |
Method: | Least Squares | F-statistic: | 103.1 |
Date: | Sun, 18 Jul 2021 | Prob (F-statistic): | 1.67e-101 |
Time: | 10:19:41 | Log-Likelihood: | -1011.6 |
No. Observations: | 354 | AIC: | 2047. |
Df Residuals: | 342 | BIC: | 2094. |
Df Model: | 11 | ||
Covariance Type: | nonrobust |
coef | std err | t | P>|t| | [0.025 | 0.975] | |
---|---|---|---|---|---|---|
Intercept | 38.8479 | 5.462 | 7.113 | 0.000 | 28.105 | 49.591 |
LSTAT | -0.5124 | 0.052 | -9.876 | 0.000 | -0.615 | -0.410 |
RM | 3.4864 | 0.441 | 7.900 | 0.000 | 2.618 | 4.354 |
PTRATIO | -0.9178 | 0.138 | -6.627 | 0.000 | -1.190 | -0.645 |
DIS | -1.4592 | 0.204 | -7.140 | 0.000 | -1.861 | -1.057 |
NOX | -18.1123 | 3.662 | -4.947 | 0.000 | -25.314 | -10.910 |
CHAS | 3.1956 | 0.894 | 3.575 | 0.000 | 1.437 | 4.954 |
CRIM | -0.1322 | 0.034 | -3.931 | 0.000 | -0.198 | -0.066 |
ZN | 0.0416 | 0.015 | 2.847 | 0.005 | 0.013 | 0.070 |
B | 0.0067 | 0.003 | 2.387 | 0.018 | 0.001 | 0.012 |
RAD | 0.2733 | 0.069 | 3.941 | 0.000 | 0.137 | 0.410 |
TAX | -0.0113 | 0.004 | -3.072 | 0.002 | -0.019 | -0.004 |
Omnibus: | 103.496 | Durbin-Watson: | 1.354 |
---|---|---|---|
Prob(Omnibus): | 0.000 | Jarque-Bera (JB): | 364.627 |
Skew: | 1.264 | Prob(JB): | 6.64e-80 |
Kurtosis: | 7.281 | Cond. No. | 1.45e+04 |
Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The condition number is large, 1.45e+04. This might indicate that there are
strong multicollinearity or other numerical problems.
网格搜索调参
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler # 由于SVR基于距离计算,引入对数据进行标准化的类
from sklearn.svm import SVR # 引入SVR类
from sklearn.model_selection import GridSearchCV # 引入网格搜索调优
pipe_svr = make_pipeline(StandardScaler(),SVR())
#参数设置
param_range = [0.0001,0.001,0.01,0.1,1.0,10.0,100.0,1000.0]
# 两个网格
# 第一个网格是具有线性(linear)内核的参数"svr__C"在param_range中取值
# 第二个网格是具有rbf内核的参数"svr__C"和"svr__gamma"分别在param_range中取值
param_grid = [{"svr__C":param_range,"svr__kernel":["linear"]}, # 注意__是指两个下划线,一个下划线会报错的
{"svr__C":param_range,"svr__gamma":param_range,"svr__kernel":["rbf"]}]
gs = GridSearchCV(estimator=pipe_svr,
param_grid = param_grid,
scoring = 'r2',
cv = 10) # 10折交叉验证
house_data.head()
CRIM | ZN | INDUS | CHAS | NOX | RM | AGE | DIS | RAD | TAX | PTRATIO | B | LSTAT | value | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0.00632 | 18.0 | 2.31 | 0.0 | 0.538 | 6.575 | 65.2 | 4.0900 | 1.0 | 296.0 | 15.3 | 396.90 | 4.98 | 24.0 |
1 | 0.02731 | 0.0 | 7.07 | 0.0 | 0.469 | 6.421 | 78.9 | 4.9671 | 2.0 | 242.0 | 17.8 | 396.90 | 9.14 | 21.6 |
2 | 0.02729 | 0.0 | 7.07 | 0.0 | 0.469 | 7.185 | 61.1 | 4.9671 | 2.0 | 242.0 | 17.8 | 392.83 | 4.03 | 34.7 |
3 | 0.03237 | 0.0 | 2.18 | 0.0 | 0.458 | 6.998 | 45.8 | 6.0622 | 3.0 | 222.0 | 18.7 | 394.63 | 2.94 | 33.4 |
4 | 0.06905 | 0.0 | 2.18 | 0.0 | 0.458 | 7.147 | 54.2 | 6.0622 | 3.0 | 222.0 | 18.7 | 396.90 | 5.33 | 36.2 |
#通过特征提取可知去除了两个特征:“INDUS”和“AGE”
extractive_house_data = house_data.drop(["INDUS","AGE"],axis=1)#去除两个特征,得到特征提取后的数据
extractive_house_data.head()
CRIM | ZN | CHAS | NOX | RM | DIS | RAD | TAX | PTRATIO | B | LSTAT | value | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0.00632 | 18.0 | 0.0 | 0.538 | 6.575 | 4.0900 | 1.0 | 296.0 | 15.3 | 396.90 | 4.98 | 24.0 |
1 | 0.02731 | 0.0 | 0.0 | 0.469 | 6.421 | 4.9671 | 2.0 | 242.0 | 17.8 | 396.90 | 9.14 | 21.6 |
2 | 0.02729 | 0.0 | 0.0 | 0.469 | 7.185 | 4.9671 | 2.0 | 242.0 | 17.8 | 392.83 | 4.03 | 34.7 |
3 | 0.03237 | 0.0 | 0.0 | 0.458 | 6.998 | 6.0622 | 3.0 | 222.0 | 18.7 | 394.63 | 2.94 | 33.4 |
4 | 0.06905 | 0.0 | 0.0 | 0.458 | 7.147 | 6.0622 | 3.0 | 222.0 | 18.7 | 396.90 | 5.33 | 36.2 |
import numpy as np
X = np.array(extractive_house_data.iloc[:,:-1])
y = np.array(extractive_house_data["value"])
gs = gs.fit(X,y)
print("网格搜索最优得分:",gs.best_score_)
print("网格搜索最优参数组合:\n",gs.best_params_)
网格搜索最优得分: 0.6125173398590795
网格搜索最优参数组合:
{'svr__C': 1000.0, 'svr__gamma': 0.001, 'svr__kernel': 'rbf'}
压缩估计——Lasso回归
LassoCV对Lasso回归调参并进行特征提取
LassoCV(eps=0.001, n_alphas=100, alphas=None, fit_intercept=True, normalize=False, precompute=‘auto’, max_iter=1000, tol=0.0001, copy_X=True, cv=None, verbose=False, n_jobs=1, positive=False, random_state=None, selection=‘cyclic’ )
- eps:指代λ 最小值与最大值的商,默认为0.001。
- n_alphas:指定λ的个数,默认为100个。
- alphas:指定具体的λ列表用于模型的运算。
- fit_intercept:bool类型,是否需要拟合截距项,默认为True。
- normalize:bool类型,建模时是否对数据集做标准化处理,默认为False。
- precompute:bool类型,是否在建模前计算Gram矩阵提升运算速度,默认为False。
- max_iter:指定模型的最大迭代次数。
- tol:指定模型收敛的阈值,默认为0.0001。
- copy_X:bool类型,是否复制自变量X的数值,默认为True。
- cv:指定交叉验证的重数。
- verbose:bool类型,是否返回模型运行的详细信息,默认为False。
- n_jobs:指定使用的CPU数量,默认为1,如果为-1表示所有CPU用于交叉验证的运算。
- positive:bool类型,是否将回归系数强制为正数,默认为False。
- random_state:指定随机生成器的种子。
- selection:指定每次迭代选择的回归系数,如果为’random’,表示每次迭代中将随机更新回归系数;如果为’cyclic’,则每次迭代时回归系数的更新都基于上一次运算。
import pandas as pd
from sklearn import linear_model #引入Lasso模型
from sklearn.model_selection import train_test_split #进行训练集和测试集的划分
from sklearn.metrics import mean_squared_error
# 数据划分
train_data = data.data
train_target = data.target
train_X,test_X,train_y,test_y = train_test_split(train_data,train_target,test_size=0.3,random_state=8)
#构造不同的lambda值
alphas = np.logspace(-4,2,200)
#设置交叉验证的参数,使用均方误差评估
lasso_cv = linear_model.LassoCV(alphas=alphas,normalize=True,cv=10,max_iter=1000)
# lasso_cv = linear_model.LassoCV(alphas=alphas,cv=10,max_iter=10000)
lasso_cv.fit(train_X,train_y)
lasso_cv.alpha_
0.0013049019780144017
#基于最佳alpha值建模
lasso = linear_model.Lasso(alpha=lasso_cv.alpha_,normalize=True,max_iter=1000)
# lasso = linear_model.Lasso(alpha=lasso_cv.alpha_,max_iter=10000)
# lasso = linear_model.Lasso(alpha=0.,max_iter=10000)
lasso.fit(train_X,train_y)
print("Lasso回归的得分为:",lasso.score(train_X,train_y))
#系数为0的个数
print('相关系数零个数为:',np.sum(lasso.coef_ == 0))
print("丢弃的特征为:",data.feature_names[lasso.coef_ == 0])
#模型评估
lasso_pred=lasso.predict(test_X)
#均方误差
MSE=mean_squared_error(test_y,lasso_pred)
print(MSE)
Lasso回归的得分为: 0.7494537619186843
相关系数零个数为: 1
丢弃的特征为: ['INDUS']
23.847822377654115
网格搜索调参
可见Lasso回归去除特征"INDUS"
pipe_svr_Lasso = make_pipeline(StandardScaler(),SVR())
#参数设置
param_range = [0.0001,0.001,0.01,0.1,1.0,10.0,100.0,1000.0]
# 两个网格
# 第一个网格是具有线性(linear)内核的参数"svr__C"在param_range中取值
# 第二个网格是具有rbf内核的参数"svr__C"和"svr__gamma"分别在param_range中取值
param_grid = [{"svr__C":param_range,"svr__kernel":["linear"]}, # 注意__是指两个下划线,一个下划线会报错的
{"svr__C":param_range,"svr__gamma":param_range,"svr__kernel":["rbf"]}]
gs_lasso = GridSearchCV(estimator=pipe_svr_Lasso,
param_grid = param_grid,
scoring = 'r2',
cv = 10) # 10折交叉验证
#通过特征提取可知去除特征:"INDUS"
extractive_house_data_Lasso = house_data.drop("INDUS",axis=1)#去除特征,得到特征提取后的数据
X_Lasso = np.array(extractive_house_data_Lasso.iloc[:,:-1])
y_Lasso = np.array(extractive_house_data_Lasso["value"])
gs_lasso = gs_lasso.fit(X_Lasso,y_Lasso)
print("网格搜索最优得分:",gs_lasso.best_score_)
print("网格搜索最优参数组合:\n",gs_lasso.best_params_)
网格搜索最优得分: 0.6220298860688059
网格搜索最优参数组合:
{'svr__C': 1000.0, 'svr__gamma': 0.001, 'svr__kernel': 'rbf'}
降维
特征提取
import numpy as np
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler #数据标准化
scaler = StandardScaler() #标准化实例
X = data.data
standard_X = scaler.fit_transform(X) #数据标准化
pca = PCA(n_components="mle")
newX = pca.fit_transform(standard_X) #等价于pca.fit(X) pca.transform(X)
# invX = pca.inverse_transform(X) #将降维后的数据转换成原始数据
# print(newX)
print("保留的{}个成分的方差百分比分别为:{}".format(pca.n_components_,pca.explained_variance_ratio_,))
# print(invX)
pca_all = PCA(n_components=13)
pca_all.fit_transform(standard_X) #等价于pca.fit(X) pca.transform(X)
print("所有的{}个成分的方差百分比分别为:{}".format(pca_all.n_components_,pca_all.explained_variance_ratio_))
保留的12个成分的方差百分比分别为:[0.47129606 0.11025193 0.0955859 0.06596732 0.06421661 0.05056978
0.04118124 0.03046902 0.02130333 0.01694137 0.0143088 0.01302331]
所有的13个成分的方差百分比分别为:[0.47129606 0.11025193 0.0955859 0.06596732 0.06421661 0.05056978
0.04118124 0.03046902 0.02130333 0.01694137 0.0143088 0.01302331
0.00488533]
网格搜索
可知通过降维丢弃的特征为“LSTAT”
pipe_svr_PCA = make_pipeline(StandardScaler(),SVR())
#参数设置
param_range = [0.0001,0.001,0.01,0.1,1.0,10.0,100.0,1000.0]
# 两个网格
# 第一个网格是具有线性(linear)内核的参数"svr__C"在param_range中取值
# 第二个网格是具有rbf内核的参数"svr__C"和"svr__gamma"分别在param_range中取值
param_grid = [{"svr__C":param_range,"svr__kernel":["linear"]}, # 注意__是指两个下划线,一个下划线会报错的
{"svr__C":param_range,"svr__gamma":param_range,"svr__kernel":["rbf"]}]
gs_PCA = GridSearchCV(estimator=pipe_svr_PCA,
param_grid = param_grid,
scoring = 'r2',
cv = 10) # 10折交叉验证
#通过特征提取可知去除特征:“LSTAT”
extractive_house_data_PCA = house_data.drop("LSTAT",axis=1)#去除特征“LSTAT”,得到特征提取后的数据
X_PCA = np.array(extractive_house_data_PCA.iloc[:,:-1])
y_PCA = np.array(extractive_house_data_PCA["value"])
gs_PCA = gs_PCA.fit(X_PCA,y_PCA)
print("网格搜索最优得分:",gs_PCA.best_score_)
print("网格搜索最优参数组合:\n",gs_PCA.best_params_)
网格搜索最优得分: 0.5310649472333082
网格搜索最优参数组合:
{'svr__C': 1000.0, 'svr__gamma': 0.001, 'svr__kernel': 'rbf'}
分析
特征提取方法在于向前逐步选择算法的使用
Lasso回归选择特征在于对Lasso回归模型中alpha的值的选择,以求得到更好的Lasso模型,从而更好的选择特征
主成分分析降维提取特征在于将所有的特征降维成多少个维度,从而选择特征
优劣
特征提取方法中没有需要自己设定的超参数,而是通过算法来选择特征,编写算法的过程相对繁琐。
Lasso回归中需要自己寻找合适的alpha值从而使得某些特征的相关系数为0,可以通过LassoCV方法来交叉验证从而选择最佳的alpha进行Lasso回归建模。
降维法中要先对数据进行标准化,再进行PCA主成分分析,在选择要提取的特征维度的时候需要自己把控,同时也要自己通过数据对比找出丢弃的特征,再进行特征选择。
通过实践,发现三种方法进行网格搜索后选择的超参数都是一样的,但是通过特征提取方法和Lasso方法进行网格搜索的得分比降维法要高,可能是降维法中选择的维度并没有适当的原因