используя длинные векторы в R с glmnet и dotCall64 - PullRequest
0 голосов
/ 08 февраля 2019

Я использую glmnet и glmnetcr, чтобы соответствовать моделям порядковой регрессии.

К сожалению, моя матрица модели составляет ~ 640000 * 5000. Это больше, чем можно сохранить в 32-битном целом числе, и я сталкиваюсь ста же проблема, которую описали другие: R ограничение размера вектора: «длинные векторы (аргумент 5) не поддерживаются в .C»

Если я использую только половину данных, я могу запуститьэто на моем локальном сервере с большим количеством памяти и без проблем.

Я попытался реализовать «решение» в вышеприведенном посте с помощью пакета dotCall64.Я заменил вызовы .Fortran на .C64 и указал тип данных для каждой переменной.Однако каждый раз, когда я запускаю свой код, я либо получаю бессмысленные лямбда-значения (9.9e35), либо сбои, такие как:

* перехвачено segfault * адрес 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 () приводит к нечетным оценкам лямбда-значений и / или ошибкам сегмента (кажется случайным, что происходит).Мое первое предположение состоит в том, что у меня неправильно введена одна из переменных, но я все дважды просмотрел и не вижу проблемы.Другой вариант заключается в том, что базовый код Fortran не может обрабатывать 64-битные целые числа.Я знаю ноль фортранов и даже не знаю, как начать решать проблему, если это так.

1 Ответ

0 голосов
/ 28 февраля 2019

Итак, я обратился к сопровождающим пакетов glmnet.У них был опыт конвертации в .C64.С их помощью и немного возиться я смог заставить работать следующий код.Для этого я создал новую функцию glmnet64, которая вместо первоначального вызова lognet вызвала другую новую функцию lognet64.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)

Ключ, похоже, получал все типы переменных, указанные правильно.Был в состоянии использовать browser () прямо перед вызовом .Fortran, чтобы получить это право.Также, улучшите скорость, указав INTENT и установив NAOK = TRUE (как и ожидалось).Определенно рекомендую их.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...