我使用 glmnet 和 glmnetcr 来拟合序数回归模型。
不幸的是,我的模型矩阵约为 640000 * 5000。这大于可以存储在 32 位整数中的大小,并且我遇到了其他人描述的相同问题:R 向量大小限制:“.C 中不支持长向量(参数 5)” https://stackoverflow.com/questions/34165654/r-vector-size-limit-long-vectors-argument-5-are-not-supported-in-c
如果我只使用一半的数据,我可以在有足够内存的本地服务器上运行它,并且不会出现任何问题。
我尝试使用 dotCall64 包来实现上面帖子中的“解决方案”。我已将 .Fortran 调用替换为 .C64,并指定了每个变量的数据类型。然而,每次运行代码时,我要么得到无意义的 lambda 值 (9.9e35),要么得到段错误,例如:
* 捕获段错误 *地址 0x1511aaeb0,导致“内存未映射”
我得到的地址和确切的地址每次都会有所不同,因此我认为我在实施此解决方案时做错了什么。
这是函数 lognet() 中迄今为止的代码(该函数最终由 glmnetcr 和 glmnet 调用,并将变量传递给 fortran 代码)
原始代码在lognet()中
.Fortran("lognet", parm = alpha, nobs, nvars, nc, as.double(x),
y, offset, jd, vp, cl, ne, nx, nlam, flmin, ulam, thresh,
isd, intr, maxit, kopt, lmu = integer(1), a0 = double(nlam *
nc), ca = double(nx * nlam * nc), ia = integer(nx),
nin = integer(nlam), nulldev = double(1), dev = double(nlam),
alm = double(nlam), nlp = integer(1), jerr = integer(1),
PACKAGE = "glmnet")
修改lognet()中的代码
.C64("lognet", SIGNATURE = c("double","int", "int", "int", "int64",
"double","double","int", "double","double"
"int", "int", "int", "double","double",
"double","int", "int", "int", "int",
"int", "double","double","int", "int",
"double","double","double","int", "int"),
parm = alpha, nobs, nvars, nc, as.double(x),
y, offset, jd, vp, cl, ne, nx, nlam, flmin, ulam, thresh,
isd, intr, maxit, kopt, lmu = integer(1), a0 = double(nlam * nc), ca = double(nx * nlam * nc), ia = integer(nx),
nin = integer(nlam), nulldev = double(1), dev = double(nlam),
alm = double(nlam), nlp = integer(1), jerr = integer(1),
PACKAGE = "glmnet")
玩具示例(数据比实际小得多)
library(glmnetcr)
library(dotCall64)
x1 <- cbind(c(0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1),c(0,0,0,1,0,1,1,1,0,0,0,0,0,1,1,1),c(0,0,1,0,1,0,1,1,0,0,0,0,1,0,1,1),c(0,1,0,0,1,1,0,1,0,0,0,0,1,1,0,1),c(0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1),c(0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,1),c(0,0,0,0,1,0,0,1,0,0,0,0,1,0,0,1))
y1 <- c(0,0,0,1,1,1,2,2,0,1,0,1,1,2,1,2)
testA <- glmnetcr(x=x1,y=y1,method = "forward", nlambda=10,lambda.min.ratio=0.001, alpha =1,maxit = 500,standardize=FALSE)
使用原始 lognet() 代码运行它不会产生任何问题。
使用修改后的 lognet() 代码运行它会导致奇怪的 lambda 值估计和/或段错误(似乎是随机发生的)。我的第一个猜测是我有一个变量输入错误,但我已经将所有内容检查了两次并且看不到问题。另一种选择是底层 Fortran 代码无法处理 64 位整数。我对 Fortran 的了解为零,甚至不知道如果是这种情况如何开始解决问题。