您说得对,在 glmnet 中设置下限是针对协变量的。泊松会将下限设置为零,因为您取幂以取回“计数”。
按照这些思路,如果您转换响应变量,它很可能会起作用。一种快速的方法是记录您的响应变量,进行拟合并将其转换回来,这将确保它始终为正。你必须处理零
另一种方法是电源转换。有很多事情要考虑,我只能尝试使用带有数据集的 two parameter box-cox,因为您没有提供您的数据集:
library(glmnet)
library(mlbench)
library(geoR)
data(BostonHousing)
data = BostonHousing
data$chas=as.numeric(data$chas)
# change it to min 0 and max 1
data$medv = (data$medv-min(data$medv))/diff(range(data$medv))
然后在这里我通过 pca 使用快速近似(不拟合所有变量)来获得合适的 lambda1 和 lambda2 :
bcfit = boxcoxfit(object = data[,14],
xmat = prcomp(data[,-14],scale=TRUE,center=TRUE)$x[,1:2],
lambda2=TRUE)
bcfit
Fitted parameters:
lambda lambda2 beta0 beta1 beta2 sigmasq
0.42696313 0.00001000 -0.83074178 -0.09876102 0.08970137 0.05655903
Convergence code returned by optim: 0
检查 lambda2,它是决定是否得到负值的关键。它应该相当小。
创建功率变换的函数:
bct = function(y,l1,l2){((y+l2)^l1 -1)/l1}
bctinverse = function(y,l1,l2){(y*l1+1)^(1/l1) -l2}
现在我们转换响应:
data$medv_trans = bct(data$medv,bcfit$lambda[1],bcfit$lambda[2])
并适合 glmnet:
fit = glmnet(x=as.matrix(data[,1:13]),y=data$medv_trans,nlambda=500)
获取所有 lambdas 的预测,一旦转换回来,您可以看到没有负面预测:
pred = predict(fit,as.matrix(data[,1:13]))
range(bctinverse(pred,bcfit$lambda[1],bcfit$lambda[2]))
[1] 0.006690685 0.918473356
假设我们与 cv 匹配:
fit = cv.glmnet(x=as.matrix(data[,1:13]),y=data$medv_trans)
pred = predict(fit,as.matrix(data[,1:13]))
pred_transformed = bctinverse(pred,bcfit$lambda[1],bcfit$lambda[2]
plot(data$medv,pred_transformed,xlab="orig response",ylab="predictions")