gpt4 book ai didi

r - 在 Glmnet 和 dotCall64 中使用 R 中的长向量

转载 作者:行者123 更新时间:2023-12-04 11:08:22 24 4
gpt4 key购买 nike

我正在使用 glmnet 和 glmnetcr 来拟合序数回归模型。

不幸的是,我的模型矩阵是 ~640000 * 5000。这大于可以存储在 32 位整数中的大小,我遇到了其他人描述的相同问题:R vector size limit: "long vectors (argument 5) are not supported in .C"

如果我只使用一半的数据,我可以在内存充足的本地服务器上运行它并且没有问题。

我试图通过使用 dotCall64 包来实现上述帖子中的“解决方案”。我用 .C64 替换了 .Fortran 调用,并为每个变量指定了数据类型。但是,每次我运行我的代码时,我都会得到无意义的 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 的了解为零,如果是这种情况,我什至不确定如何开始解决问题。

最佳答案

所以我联系了 glmnet 的包维护者。他们有转换为 .C64 的经验。在他们的帮助和一点点摆弄下,我能够让下面的代码工作。为了运行它,我创建了一个名为 glmnet64 的新函数,它调用了另一个新函数 lognet64 而不是原来的 lognet 调用。 lognet64 与原始 lognet 函数相同,但用以下内容替换了 .Fortran 调用:

.C64("lognet", SIGNATURE =   c("double", "integer","integer","integer","double",
"double", "double", "integer","double", "double",
"integer","integer","integer","double", "double",
"double", "integer","integer","integer","integer",
"integer","double", "double", "integer","integer",
"double", "double", "double","integer","integer"),
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),
INTENT = c(rep("rw",4),"r",rep("rw",15),rep("w",10)),
PACKAGE = "glmnet",
NAOK = TRUE)

关键似乎是正确指定所有变量类型。能够在 .Fortran 调用之前使用 browser() 来获得正确的结果。此外,通过指定 INTENT 和设置 NAOK = TRUE(如预期)来提高速度。肯定会推荐那些。

关于r - 在 Glmnet 和 dotCall64 中使用 R 中的长向量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54599793/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com