2013-06-10 25 views
18

Ho un problema per eseguire glmnet lasso con un ampio set di dati. I miei dati hanno N = 50, ma p> 49000, tutti i fattori. Quindi per eseguire glmnet devo creare un model.matrix, ma ho appena finito la memoria quando chiamo model.matrix (formula, data), dove formula = Class ~.Grande matrice per eseguire glmnet()

Come esempio pratico io generare un set di dati:

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) 

Dopo che ho cercato di creare un model.matrix immettere sui glmnet.

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

Nell'ultimo stadio (X = model.matrix ...) i corto di memoria. Cosa posso fare?

+0

Tempo per più RAM. (Oppure riavvia con un insieme minimo di applicazioni e dati.) Questo è solo un oggetto largo 24MB. –

+0

Beh, ho solo 50 campioni. Non posso credere che non ci sia soluzione! –

+0

Non ho detto che non c'era soluzione. –

risposta

22

ho chiesto il professor Trevor Hastie e ha ricevuto i seguenti consigli:.

"Ciao Flavio

model.matrix ti sta uccidendo Avrete 49K fattori, e la matrice modello è cercare di rappresentarli come contrasti che saranno 6 matrici di colonne, quindi 49 * 6 circa 300 colonne K. Perché non creare variabili fittizie binarie (7 per fattore) e semplicemente costruirlo direttamente senza utilizzare model.matrix. È possibile salvare 1/7 dello spazio memorizzando questo tramite sparseMatrix (glmnet accetta i formati a matrice sparsa) "

Ho fatto esattamente questo e ha funzionato perfettamente bene. Penso che possa essere utile agli altri.

Un articolo, con il codice, che è venuto formare questo problema: http://www.rmining.net/2014/02/25/genetic-data-large-matrices-glmnet/

Al fine di evitare collegamenti interrotti mi post parte del post qui:

Il problema con l'approccio formula è che, in generale, i dati genomici hanno più colonne che osservazioni. I dati che ho lavorato in quel caso avevano 40.000 colonne e solo 73 osservazioni. Al fine di creare un piccolo insieme di dati di test, eseguire il codice seguente:

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) 

Così, con questo insieme di dati cercheremo di adattare un modello con glmnet():

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

E se non hai un computer con più RAM del mio, probabilmente perderai memoria e causerai un crash in R. La soluzione? La mia prima idea era provare sparse.model.matrix() che crea un modello di matrice sparsa usando la stessa formula. Purtroppo non ha funzionato, perché anche con la matrice sparsa, il modello finale è ancora troppo grande! È interessante notare che questo set di dati occupa solo 24 MB di RAM, ma quando si utilizza model.matrix il risultato è un array con più di 1 GB.

La soluzione che ho trovato era di costruire la matrice a portata di mano. Per fare ciò codifichiamo la matrice con variabili dummy, colonna per colonna, e memorizziamo il risultato in una matrice sparsa. Poi useremo questa matrice come input per il modello e vedere se non perderà la memoria:

## 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) 
} 

NOTA: Prestare attenzione a come stiamo usando una matrice sparsa è necessario il pacchetto di Matrix. Si noti inoltre che le colonne sono connesse usando cBind() invece di cbind().

La matrice così generata era molto più bassa: meno di 70 Mb quando ho provato.Fortunatamente glmnet() supporta una matrice sparsa ed è possibile eseguire il modello:

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

in modo da poter creare modelli con questo tipo di dati senza dilapidare la memoria e senza pacchetti di utilizzare R per grandi quantità di dati, come bigmemory e ff.

+1

potresti anche provare 'Matrix :: sparse.model.matrix' o' MatrixModels :: modelMatrix (*, sparse = TRUE) ' –

+0

Che non funziona !!! Prova tu stesso con l'esempio. L'oggetto creato con sparse.model.matrix è molto più grande. L'ho provato prima di pubblicare questa domanda. –

+0

oh beh ... è strano, mi chiedo perché no. –

1

A chi potrebbe essere interessato. Ho sviluppato un pacchetto R chiamato biglasso che si adatta ai modelli di tipo lasso con Big Data. Funziona con una matrice di progettazione mappata alla memoria (grande) basata sul pacchetto bigmemory e può funzionare senza problemi per i casi di dati più grandi della RAM. Inoltre, è più efficiente in termini di elaborazione e memoria rispetto a glmnet utilizzando le nuove regole di screening delle funzioni proposte e una migliore implementazione. Si prega di controllare the GitHub page per i dettagli, e non esitate a fornire suggerimenti/commenti.

Problemi correlati