在我的数据集中,我有一些连续变量和虚拟变量。在使用glmnet进行分析时,我希望标准化连续变量,但不希望标准化虚拟变量。
目前,我是手动完成这个操作的,首先定义一个只包含[0,1]值的列的虚拟向量,然后对所有非虚拟列使用scale
命令。问题是,这种方法不够优雅。
但是,glmnet有一个内置的standardize
参数。默认情况下,这会标准化虚拟变量吗?如果是的话,有没有一种优雅的方法可以告诉glmnet的standardize
参数跳过虚拟变量?
回答:
简而言之,是的——这会标准化虚拟变量,但这样做是有原因的。glmnet
函数以矩阵作为其X
参数的输入,而不是数据框,因此它不会区分factor
列,这些列在参数为data.frame
时可能会有。如果你查看R函数,你会发现glmnet内部将standardize
参数编码为
isd = as.integer(standardize)
这将R的布尔值转换为0或1的整数,以供任何内部的FORTRAN函数(如elnet、lognet等)使用。
如果你进一步查看FORTRAN代码(固定宽度 – 老派风格!),你会看到以下代码块:
subroutine standard1 (no,ni,x,y,w,isd,intr,ju,xm,xs,ym,ys,xv,jerr) 989 real x(no,ni),y(no),w(no),xm(ni),xs(ni),xv(ni) 989 integer ju(ni) 990 real, dimension (:), allocatable :: v allocate(v(1:no),stat=jerr) 993 if(jerr.ne.0) return 994 w=w/sum(w) 994 v=sqrt(w) 995 if(intr .ne. 0)goto 10651 995 ym=0.0 995 y=v*y 996 ys=sqrt(dot_product(y,y)-dot_product(v,y)**2) 996 y=y/ys 997 10660 do 10661 j=1,ni 997 if(ju(j).eq.0)goto 10661 997 xm(j)=0.0 997 x(:,j)=v*x(:,j) 998 xv(j)=dot_product(x(:,j),x(:,j)) 999 if(isd .eq. 0)goto 10681 999 xbq=dot_product(v,x(:,j))**2 999 vc=xv(j)-xbq 1000 xs(j)=sqrt(vc) 1000 x(:,j)=x(:,j)/xs(j) 1000 xv(j)=1.0+xbq/vc 1001 goto 10691 1002
查看标记为1000的行——这基本上是将标准化公式应用于X
矩阵。
从统计学角度来说,人们通常不会标准化分类变量,以保持估计回归系数的可解释性。然而,正如Tibshirani 在这里指出的那样,“套索方法需要对回归变量进行初始标准化,以便惩罚方案对所有回归变量公平。对于分类回归变量,人们用虚拟变量对回归变量进行编码,然后标准化这些虚拟变量”——因此,尽管这会导致连续变量和分类变量之间的任意缩放,但这是为了平等的惩罚处理而进行的。