Generalized additive model (简称GAM)在1986年由Hastie & Tibshirani发表以后,一直被应用于许多领域,如环境科学、医学、生物统计,在方法上也得到发展,如Amato等人(2002)提出的基于傅立叶变换最优逼近模式估计,Sardy(2003)基于非线性小波估计方法,范剑青2004年提出的基于核函数的广义可加模型估计以及基于GLR的统计推断,对可加模型的估计和统计推断做了进一步的发展,而且在应用上该方法也被拓展到经济金融领域,Wensui Liu在2007年提出了基于GAM的信用评分模型改进无疑是该方法在金融实践中的一个成功的尝试,在不久的将来也许非参数计量将会是下一代计量理论体系的核心补丁。
下面说说GAM方法的优势,首先它没有参数方法对先验分布的限制前提(如normalassumption、homoscedasticity assumption),其次在处理非线性模式的能力要远远强于参数模型,当然新的模式出现也会给我们的应用增添一些疑惑,比如在可加成分是否显著或如何判断自变量与因变量间是线性还是非线性模式,基于这个问题,理论学者和应用大牛们也都分别给出了相应的方法和尝试,比如范剑青的GLR检验、profile least-squares estimation,Hastie的Back-Fitting and Local Scoring Algorithms,他们的方法本质上都是基于非参数部分的局部分解以及整体模式残差最小的思想,如果因变量是二分变量估计方法相应替换成似然方法便是。
接下来给出相应的估计和检验方法,之前博客里已经给出范剑青的核方法的半变系数非参数模型的估计和检验程序(理论可以参考Profile Likelihood inferences on Semiparametric Varying-coeffcient Partially Liner Models),接下来介绍基于SAS集成的程序(更灵活简单)。
先介绍下GAM 基本的概念。一般线性模式可如下所示:
E(Y)=b0+b1*X1+b2*X2+...+bp*Xp
但在 GAM 下,模式相应改为:
E(Y)=s0+s1(X1)+s2(X2)+...+sp(Xp)
其中 si(Xi) 为smooth function(平滑函数)。值得注意的是这个方程式没有确定的模式,而以 non-parametric 的形态去估计。SAS的过程布中采用「backfitting algorithm」。由于 GAMscore equation 没有close form,所以必须依赖backfitting algorithm回溯拟合或构建估出si(Xi)的局
部核函数。
接下来采用Dong Xiang 在 SUGI 26发表的文章里的案例简要说明Proc GAM的使用。Xiang 引用了 Bell et al. 在1989 年的一份有关推背的相关数据,其反应变量是个二分类变量(有(1)和无(0))。三個预测变量分别是 Age, StartVert和 NumVert。
sas估计程序:
PROC GAM data=kyphosis;
model kyphosis = spline(NumVert,df=3)
spline(Age,df=3)
spline(StartVert,df=3)
/dist=logist;
output out=estimate pred uclm lclm;
run;
其中spline是平滑方式,可用loess和spline2代替,三者的解释为:spline的平滑方式为cubic spline,即三次样条逼近,loess为局部估计(即为核估计),spline2是bivariate thin-plate smoothing;语法分别为:SPLINE(variable<,df=number>),loess(variable<,df=number>),SPLINE2(variable,variable<,df=number>),其中df为平滑统计量的自由度,缺省为4,可以自己指定,在option添加GCV(广义交叉确认)时不需在平滑函数中指定自由度,可以自动确定各变量的最优自由度。如果有的变量与因变量为线性关系,也可以通过param(variable(s))指定参数变量,如果一个回归模型中既有param又有loess部分的话,模型即为半参数模型,proc gam过程目前还不支持系数为非参数函数的模型。当因变量为二分类变量时,模型变是logistic additive model,需要通过制定link function进行拟合,利用dist option指定依赖变量的分布模式,即设定dist=logist,如果link function为dist=log时,则模式即为poission model。文中kyphosis为二分类变量,故而指定logist为连接函数。
注:dist可以是GAUSSIAN, BINOMIAL, BINARY, GAMMA, or POISSON.
另外OUTPUT statement 可以将参数估计、非参数平滑预测值、目标变量的预测概率和其 95% 置信区间分别给出(pred uclm lclm)并产生新变量。估计的数据可以用来做图。
先看下输出结果,第一部分是summary statistics,提供一些参数估计过程的信息,如下:
目标变量为二项分布(binomial),连接函数为logist,局部评分迭代9次等。接下来看下第二部分的输出结果:
这部分包含三张报表。第一个表示模式的线性部分的参数估计值(包含非参数的线性分解部分,具体会在后面介绍)。第二个是用 GAM 跑出的 smoother 即窗宽值。第三个表比较特别。此处利用 deviance analysis检验比较full model(包含全部 smoothing function)和 reduced model(少掉某一个smoothing function)那個统计量的检验结果(这正是GLR的核心思想,范剑青在2005的一篇文献中证明,这个似然统计量遵从wilks现象,即服从卡方分布,在具体应用中可根据卡方分布拟合及Bootstrap具体判断参数的显著推断)。所以零假设 H0: reduce model vs H1: full model。如果的 p-value小于0.05 則表示拒绝 reduced model。反之则表示不拒绝 reduce model。以 Age 和 StartVert 来看,两者的 p-value 分別是 0.0009 和 0.0350,皆小于0.05。所以可以同时分別少了这两个变量的 reduced model(对比参数模型中b=0的假设)。而 NumVert 的 p-value 为0.3311 > 0.05,表示不拒绝少了 NumVert 的 smoothing function 的reduced model,也就是说f(NumVert) 在模式中不显著。
很多人可能会疑问,程序中设定的变量均为非参数形式为何输出的结果会有回归结果的parameter估计值和非参数部分的smoothing parameter,这得从gam过程的估计原理说起:当模型设定为下式时
model y = param(z) spline(x1) spline(x2)
则表示估计的模型为y = a0 + a1*z + s1(x1) + s2(x2),而GAM过程实际估计的是y = a0 + a1*z + b1*x1+f1(x1) + b2*x2 + f2(x2),其中s1(x1) = b1*x1 + f1(x1), GAM 分离出线性趋势项和非参数的平滑函数f1(x1),其中线性部分决定自变量的主要趋势,非参数部分为调整项。
所以上述输出结果中 “Regression Model Analysis” with “Parameter Estimates” 就是a0 (labeled Intercept)的估计值,,a1 (labeled z),,b1 (labeled L_X1 for the linear part of x1,例子中的age),and b2 (labeled L_X2,例子中的startvert)等等。在程序的output设定中的Pred会在结果数据集中自动输出非参数的估计部分:
P_Y = a0 + a1*z + b1*x1+f1(x1) + b2*x2 + f2(x2)
P_X1 = f1(X1)
P_X2 = f1(X2)
故而,非参数部分的full partial prediction即为:b1*x1+p_X1às(x1),b2*x2+p_x2às(x2);总体的预测必须在data步完成,或在proc步中添加score语句。
另附半参数回归估计和基于bootstrap参数检验程序:
%%****程序说明:SAS IML的半变系数部分线性模型的非参数估计其中,x1,x2为可变部分,z1-z3为线性部分。Reference:
Profile Likelihood Inferences on Semiparametric Varying-Coefficient Partially Linear Models
by Jianqing Fan****
%let x=%bquote(x1 x2);
%let z=%bquote(z1 z2 z3);
%let dataset=simul_dataset;
%let varnum=2;
proc iml;
use &dataset;
read all into u var{u};
read all into x var{&x};
read all into z var{&z};
read all into y var{y};
close &dataset;
sort &dataset out=data_set0 by u;
use data_set0;
read all into u1 var{u};
n=nrow(x);
x1=j(n,1,1);
x=x1||x;
%let vary_var=%eval_r(&varnum+1);
*define kernel function*
start kde(o);
kernel=0.75*(1-o##2)#(abs(o<=1));
return(kernel);
finish;
* Varying partly linear model estimation*
start S_metric(_y,u0,u10,_n,x0,z0,vary_var0);
mean=u0[:,];
stderr=sqrt((u0-mean)[##,]);
h=2.34#stderr#_n##(-0.2);
I=i(_n);
do j=1 to _n;
k0=(u0-u10[j,])/h;
w0=(1/h)#kde(k0);
w=diag(w0);
hx=(u0-u10[j,])/h;
hhx=hx#x0;
du=x0||hhx;
l=(x0[j,]||j(1,vary_var0,0))*inv(t(du)*w*du)*t(du)*w;
s=s//l[1,];
end;
return(s);
finish S_metric;
****define the estimation bhat****
start Para(_y,u0,u10,_n,x0,z0,vary_var);
I=i(_n);
S=S_metric(_y,u0,u10,_n,x0,z0,vary_var);
****linear part estimation****
bhat=inv(t(z0)*t(I-s)*(I-s)*z0)*t(z0)*t(I-s)*(I-s)*_y;
return(bhat);
finish Para;
***Define the varying-coefficient named E****
start vary_para(_y,u0,u10,_n,x0,z0,vary_var);
bhat=para(_y,u0,u10,_n,x0,z0,vary_var);
mean=u0[:,];
stderr=sqrt((u0-mean)[##,]);
h=2.34#stderr#_n##(-0.2);
do i=1 to _n;
k1=(u0-u10[i,])/h;
w0=(1/h)#kde(k1);
w=diag(w0);
hx=(u0-u10[i,])/h;
hhx=hx#x0;
du=x0||hhx;
ahat=inv(t(du)*w*du)*t(du)*w*(_y-z0*bhat);
**** 按照有无截距项和可变系数个数决定并修改****
if i=1 then e=ahat[1,]||ahat[2,]||ahat[3,];
else e=e//(ahat[1,]||ahat[2,]||ahat[3,]);
end;
return(e);
finish vary_para;
****Get resid of vary_semi estimation***
start resid_boot(_y,u0,u10,_n,x0,z0,vary_var);
bhat=para(_y,u0,u10,_n,x0,z0,vary_var);
S=S_metric(_y,u0,u10,_n,x0,z0,vary_var);
resid_boot=_y-s*(_y-z0*bhat)-z0*bhat;
return(resid_boot);
finish resid_boot;
****Get the PLR statistic****
******Hypothsis testing for Parametric part,Statistic:PLR
firstly,Estimate Parametric part********
* where vary_var is not the same only*
start test_H(_y,u0,u10,_n,x0,z0,vary_var0,vary_var1);
bhat=para(_y,u0,u10,_n,x0,z0,vary_var0);
e=vary_para(_y,u0,u10,_n,x0,z0,vary_var0);
S=S_metric(_y,u0,u10,_n,x0,z0,vary_var0);
m_1=s*(_y-z0*bhat);
raw_rss1=_y-m_1-z0*bhat;
rss_1=raw_rss1[##,];
dim_z=ncol(z0);
do p=1 to dim_z;
*** Take metric Z with pth observation deleted ***;
nobs_bhat=nrow(bhat);
if p=1 then do;
***** _BHATdel_=bhat[2:nobs_bhat,]; ****
_Zdel_=z0[,2:ncol(z0)];
end;
else if p=nobs_bhat then do;
**** _BHATdel_=bhat[1:(nobs_bhat-1),];****
_Zdel_=z0[,1:ncol(z0)-1];
end;
else do;
***8*_BHATdel_=bhat[1:(p-1),]//bhat[(p+1):nobs_bhat,];*****
_Zdel_=z0[,1:p-1]||z0[,(p+1):ncol(z0)];
end;
bhat0=para(_y,u0,u10,_n,x0,_zdel_,vary_var0);
e0=vary_para(_y,u0,u10,_n,x0,_zdel_,vary_var0);