数据挖掘|偏差方差分解&模型评价标准

目录

提供了一种关键思想:偏差-方差分解,以及几个模型评价标准。

一、基本原理

假定的真实模型为其中$E(\epsilon)=0,V(\epsilon)={\sigma}^{2}.$

对给定训练集$\{(x_{i},y_{i})\}$下训练出的假设$h(x)=ax+b$,我们通过预测误差$E_{P}{(y^{}-h(x^{}))}^{2}$对其进行评价

二、基本思路及待讨论解决问题

我们假定训练集样本点的概率分布满足$E_{P}[Z]=\underline{Z}$,于是

然后用足够多的训练样本点$(x_i^,y_i^)$去评价假设$h(x)$,对每个给定的$(x_i^,y_i^)$,有

于是我们可以得到对假定模型$h(x)=ax+b$最终的评价

下面我们用程序来完成这个过程,并在这个基础上讨论当误差项$\epsilon$的方差${\sigma}^{2}$变化时,$h(x)$复杂度的选择问题。

三、代码部分

代码思路

真实函数其中$\epsilon\sim N(0,\sigma^2)$。对$f(x) = 2{e}^x$进行泰勒展开,有

于是选择不同光滑度的函数h(x)进行训练,下列公式光滑度由低到高:

代码内容

自定义函数lml

函数$lml$的输入为训练集TR与测试集TE,输出为以TR为训练集训练出的$h(x)$关于TE的预测集。

TR和TE变量结构相同,TR为训练集,TE为测试集,第一个均为因变量

mlm以向前法的顺序,添加自变量,建立相应的回归模型,并给出与之对应的TE的因变量的预测值

预测结果排列为1个向量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
mlm <- function(TR, TE){
vname = names(TR)
yn=vname[1] #因变量名称
xn=vname[-1] #自变量名称
mp=length(xn) #自变量的维数

ypr=NULL
tm=paste(yn,xn[1],sep="~") #将因变量y和第一个自变量粘贴成y~x.1的形式,建立lm函数。
fam=formula(tm) #公式化
cp=1
repeat{
lm1 = lm(fam,TR) #运用公式化后的lm函数对训练集TR做回归,得到相应的回归系数。
ypr=c(ypr,predict(lm1,TE)) #给出与之对应的TE的因变量的预测值

#使用向前法,依次添加自变量x.2、x.3、……、x.p,重新建立lm函数。
if(cp>=mp) break
cp=cp+1
tm=paste(tm,xn[cp],sep="+")
fam=formula(tm)
}
as.vector(ypr) #返回结果为TE的因变量的预测值,其为一个拉直的向量。
}

自定义函数BV

计算给定光滑度和方差后得到的预测函数的偏差bias和方差variance

有k个样本量为n的训练集dataTR,与一个样本量为N的测试集dataTE,其中p为做线性回归的自变量的最高阶数,$\sigma$为随机误差的标准差

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
library(plyr)
BV <- function(p, sigma, N, n, k){

##构造两个结构相同的数据集,其中自变量维数均为p,第一个均为因变量
#构造样本数为N的测试集dataTE
nx <- runif(N,-1,1) #一个样本数为N的均匀分布的随机数
ny <- 2*exp(nx)+rnorm(N,0,sigma) #真实函数为y = 2*exp(x)+epsilon 其中epsilon~N(0,sigma^2)
nz <- matrix(nx,N,p) #构造一个自变量矩阵,其中自变量维数为p,样本数为N
for(i in 2:p) nz[,i] <- 10*nz[,i]*nz[,i-1] #乘10为了量纲不要差太多,因为是(0,1)间的,平方会差很多
dataTE <- data.frame(y=ny,z=nz)

#构造样本数为n*k的训练集dataTR
x <- runif(n * k,-1,1)
y <- 2 * exp(x) + rnorm(n*k,0,sigma)
z <- matrix(x,n*k,p)
for(i in 2:p) z[,i]=10*z[,i]*z[,i-1];
dataTR <- data.frame(y=y,z=z)


index <- rep(1:k,rep(n,k))

##使用自定义函数mlm,对样本量为n的训练集dataTR做关于自变量x从1到p阶的线性回归
##得到与之对应的关于测试集dataTE的预测。
##重复k次,计算偏差和方差。
PRE=daply(dataTR, .(index), mlm, TE = dataTE) #预测值,为一个k*(N*p)的矩阵
b = ( apply(PRE,2,mean) - rep(2*exp(nx),p) )^2 #(E(h(x))-f(x))^2
b = matrix(b, nrow=N, byrow=F) #按列排成N*p的矩阵,第j列的对应的回归模型的自变量最高阶数为j
b = apply(b, 2, mean) #求不同阶数对应的预测函数的偏差,E[(E(h(x))-f(x))^2]
v = apply(PRE, 2, var) #var(h(x))
v = matrix(v, nrow=N, byrow=F) #按列排成N*p的矩阵,第j列的对应的回归模型的自变量最高阶数为j
v = apply(v,2,mean) #求不同阶数对应的预测函数的方差,E[var(h(x))]
mse= b+v

list(mse=mse, bias=b, var=v)

}

模型复杂度选取

使用自定义函数,分别计算误差项方差$\sigma^2$为$1^2、5^2和10^2$时,不同光滑度对应预测函数$h(x)$的Bias和Variance,对比不同复杂度下模型的优劣。

1
2
3
4
5
6
7
8
#定义训练集、测试集的容量、阶数p和sigma的取值
N=2000; k=2000; n=500
msigma=c(1,5,10)
NL=length(msigma)
ps=cbind(3,msigma)

print(NL)
print(ps)
1
2
3
4
5
6
7
8
9
10
#计算不同h(x)的bias和variance
set.seed(1)
timestart <- Sys.time()

#每一次循环均为给定一个sigma,使用自定义函数BV计算最高阶数为p时的偏差和方差
for(nl in 1:NL) print(BV(ps[nl,1],ps[nl,2], N, n, k))

timeend <- Sys.time()
runningtime <- timeend-timestart
print(runningtime) #计算运行时间

结论

1. 偏差Bias

Bias度量了模型预测期望函数和真实函数的偏离程度,体现了模型的拟合效果

在给定较低的噪声方差$sigma^2$时,偏差会随着模型复杂度的增加而减少;
而当噪声方差过高时,模型复杂度的增加会导致预测函数偏离真实函数,即偏差增加。

2. 方差Variance

Variance表示不同的训练数据集训练出的差异,体现了模型的稳定性
随着模型复杂度的增加,模型的简洁和稳定性均会下降,这体现在方差的增加上。

模型评价与相关指标

1. 推广误差及期望推广误差

记基于样本$L,$ 我们通过某个方法或者算法, 例如最小二乘法得到模型$h(x;L).$

  • 推广误差为
  • 期望推广误差为

2. 误差估计方法(测试误差)

  • 数据挖掘实践中通常按照7:3的比例把原始的样本分为训练集和测试集,基于训练集训练模型,基于测试集评价模型,评价误差被称为测试误差.
  • 可以认为测试误差在估计推广误差,也可以认为在估计期望推广误差. 如果原始训练集如果大,上述两种看法事实上均可以. 为什么呢?

3. 交叉验证误差

  • 交叉验证误差指把原始数据分为$K$折, 每次去掉原始数据中的一折,构建模型,并用去掉的那折评价模型, 最后再把$K$个误差平均. $K$越大, 越接近在评价推广误差,$K$越小(当然不能太小), 越接近在评价期望推广误差.
  • 如果不能理解后半句,试着把期望推广误差的定义中两个期望换序.

4. Bootstrap误差

  • Bootstrap误差和交叉验证误差类似,每次从原始数据中有放回抽取和原始数据样本量大小一致的自助训练集,训练模型,使用原始数据中未进入自助训练集的数据评价模型.
  • 重复多次,计算平均误差,即Bootstrap误差.

5. AIC

  • $AIC = n\log(RSS/n) + 2k + C$
  • AIC在什么情况下可以用?

本文链接: https://konelane.github.io/2019/03/06/190306偏差方差分解&模型评价/

-- EOF --

¥^¥请氦核牛饮一盒奶~suki