Подтвердить что ты не робот

Большая матрица для запуска glmnet()

У меня возникла проблема с запуском glmnet lasso с широким набором данных. Мои данные имеют N = 50, но p > 49000, все факторы. Поэтому для запуска glmnet мне нужно создать model.matrix, НО у меня просто закончилась память, когда я вызываю model.matrix(формулу, данные), где formula = Class ~.

В качестве обработанного примера я создам набор данных:

data <- matrix(rep(0,50*49000), nrow=50)
for(i in 1:50) {
x = rep(letters[2:8], 7000)
y = sample(x=1:49000, size=49000)
data[i,] <- x[y]
}

data <- as.data.frame(data)
x = c(rep('A', 20), rep('B', 15), rep('C', 15))
y = sample(x=1:50, size=50)
class = x[y]
data <- cbind(data, class)

После этого я попытался создать model.matrix для ввода в glmnet.

  formula <- as.formula(class ~ .)
  X = model.matrix(formula, data)
  model <- cv.glmnet(X, class, standardize=FALSE, family='multinomial', alpha=1, nfolds=10)

На последнем этапе (X = model.matrix...) у меня закончилась нехватка памяти. Что я могу сделать?

4b9b3361

Ответ 1

Я спросил профессора Тревора Хэсти и получил следующий совет:

"Привет Флавио

model.matrix убивает вас. У вас будет 49K факторов, а модельная матрица пытается представить их как контрасты, которые будут иметь 6 столбцовых матриц, поэтому 49 * 6 приблизительно 300K столбцов. Почему бы не сделать двоичные фиктивные переменные (7 на коэффициент) и просто построить это напрямую, не используя model.matrix. Вы можете сохранить 1/7-е место, сохранив это через sparseMatrix (glmnet принимает разреженные матричные форматы) "

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

В статье с кодом, который появился, возникла эта проблема: http://www.rmining.net/2014/02/25/genetic-data-large-matrices-glmnet/

Чтобы избежать неработающих ссылок, я опубликую часть сообщения здесь:

Проблема с формульным подходом заключается в том, что в целом геномные данные имеют больше столбцов, чем наблюдений. Данные, которые я работал в этом случае, имели 40 000 столбцов и всего 73 наблюдения. Чтобы создать небольшой набор тестовых данных, запустите следующий код:

for(i in 1:50) {
    x = rep(letters[2:8], 7000)
    y = sample(x=1:49000, size=49000)
    data[i,] <- x[y]
}

data <- as.data.frame(data)
x <- c(rep('A', 20), rep('B', 15), rep('C', 15))
y <- sample(x=1:50, size=50)
class = x[y]
data <- cbind(data, class)

Итак, с этим набором данных мы попытаемся установить модель с помощью glmnet():

formula <- as.formula(class ~ .)
X <- model.matrix(formula, data)
model <- cv.glmnet(X, class, standardize=FALSE, family='multinomial', alpha=1, nfolds=10)

И если у вас нет компьютера с большей оперативной памятью, чем у меня, вы, вероятно, будете течь из памяти и дать сбой в R. Решение? Моя первая идея состояла в том, чтобы попробовать sparse.model.matrix(), который создает разреженную матричную модель, используя ту же формулу. К сожалению, это не сработало, потому что даже с разреженной матрицей окончательная модель все еще слишком велика! Интересно, что этот набор данных занимает всего 24 МБ из ОЗУ, но при использовании model.matrix результатом является массив с более чем 1 ГБ.

Решение, которое я нашел, это построить матрицу под рукой. Для этого мы кодируем массив с фиктивными переменными, столбцом по столбцу и сохраняем результат в разреженной матрице. Затем мы будем использовать эту матрицу в качестве входных данных для модели и посмотреть, не будет ли она утечки памяти:

## Creates a matrix using the first column
X <- sparse.model.matrix(~data[,1]-1)

## Check if the column have more then one level
for (i in 2:ncol(data)) {

## In the case of more then one level apply dummy coding 
if (nlevels(data[,i])>1) {
    coluna <- sparse.model.matrix(~data[,i]-1)
    X <- cBind(X, coluna)
}
## Transform fator to numeric
else {
   coluna <- as.numeric(as.factor(data[,i]))
   X <- cBind(X, coluna)
}

ПРИМЕЧАНИЕ. Обратите внимание на то, как мы используем разреженную матрицу, требуется пакет Matrix. Также обратите внимание, что столбцы подключаются с помощью cBind() вместо cbind().

Полученная таким образом матрица была намного ниже: менее 70 Мб при тестировании. К счастью, glmnet() поддерживает разреженную матрицу, и вы можете запустить модель:

mod.lasso <- cv.glmnet(X, class, standardize=FALSE, family='multinomial', alpha=1, nfolds=10)

Таким образом, вы можете создавать модели с данным типом данных без раздувания памяти и без использования пакетов R для больших наборов данных, таких как bigmemory и ff.

Ответ 2

Кому может быть интересно. Я разработал пакет R под названием biglasso, который подходит для моделей типа Lasso с большими данными. Он работает с матричной матрицей с размером памяти (большой), основанной на пакете bigmemory, и может беспрепятственно работать для случаев с данными, большими, чем RAM. Более того, он более эффективен для вычислений и памяти по сравнению с glmnet, используя новые правила экранирования функций, а также лучшую реализацию. Пожалуйста, просмотрите страницу GitHub для подробностей и не стесняйтесь предлагать любые предложения и комментарии.