2013-02-26 4 views
11

Ok, questo è strano. Sospetto che si tratti di un bug all'interno di data.table, ma sarebbe utile se qualcuno può spiegare il motivo per cui ciò sta accadendo - che cosa fa esattamente update?Perché utilizzare l'aggiornamento su un lm all'interno di un gruppo data.table che perde i dati del modello?

Sto usando il trucco list(list()) all'interno di data.table per memorizzare i modelli installati. Quando si crea una sequenza di oggetti lm ciascuno per diversi raggruppamenti e quindi update tali modelli, i dati del modello per tutti i modelli diventano quelli dell'ultimo raggruppamento. Sembra che un riferimento si aggiri da qualche parte dove dovrebbe essere stata creata una copia, ma non riesco a trovare dove e non riesco a riprodurlo al di fuori di lm e update.

Esempio concreto:

Partendo con i dati dell'iride, per prima cosa i tre specie diverse dimensioni del campione, quindi montare un modello lm a ciascuna specie, l'aggiornamento quei modelli:

set.seed(3) 
DT = data.table(iris) 
DT = DT[rnorm(150) < 0.9] 
fit = DT[, list(list(lm(Sepal.Length ~ Sepal.Width + Petal.Length))), 
      by = Species] 
fit2 = fit[, list(list(update(V1[[1]], ~.-Sepal.Length))), by = Species] 

Il tabella dati originale ha numeri diversi per ogni specie

DT[,.N, by = Species] 
#  Species N 
# 1:  setosa 41 
# 2: versicolor 39 
# 3: virginica 42 

E il prima fit conferma thsi:

fit[, nobs(V1[[1]]), by = Species] 
#  Species V1 
# 1:  setosa 41 
# 2: versicolor 39 
# 3: virginica 42 

Ma la seconda in forma aggiornata sta mostrando 42 per tutti i modelli

fit2[, nobs(V1[[1]]), by = Species] 
#  Species V1 
# 1:  setosa 42 
# 2: versicolor 42 
# 3: virginica 42 

Possiamo anche guardare l'attributo di modello che contiene i dati utilizzati per il montaggio, e vedere che tutto il modello sta effettivamente utilizzando i dati dei gruppi finali. La domanda è: com'è successo?

head(fit$V1[[1]]$model) 
# Sepal.Length Sepal.Width Petal.Length 
# 1   5.1   3.5   1.4 
# 2   4.9   3.0   1.4 
# 3   4.7   3.2   1.3 
# 4   4.6   3.1   1.5 
# 5   5.0   3.6   1.4 
# 6   5.4   3.9   1.7 
head(fit$V1[[3]]$model) 
# Sepal.Length Sepal.Width Petal.Length 
# 1   6.3   3.3   6.0 
# 2   5.8   2.7   5.1 
# 3   6.3   2.9   5.6 
# 4   7.6   3.0   6.6 
# 5   4.9   2.5   4.5 
# 6   7.3   2.9   6.3 
head(fit2$V1[[1]]$model) 
# Sepal.Length Sepal.Width Petal.Length 
# 1   6.3   3.3   6.0 
# 2   5.8   2.7   5.1 
# 3   6.3   2.9   5.6 
# 4   7.6   3.0   6.6 
# 5   4.9   2.5   4.5 
# 6   7.3   2.9   6.3 
head(fit2$V1[[3]]$model) 
# Sepal.Length Sepal.Width Petal.Length 
# 1   6.3   3.3   6.0 
# 2   5.8   2.7   5.1 
# 3   6.3   2.9   5.6 
# 4   7.6   3.0   6.6 
# 5   4.9   2.5   4.5 
# 6   7.3   2.9   6.3 
+1

Questo comportamento può essere ricreato un po 'più semplicemente con questo: 'm1 <- fit $ V1 [[2]]; m2 <- update (m1,. ~.) '; 'm1' e' m2' sono quindi diversi. Forse questo ti aiuterà a capirlo. – Aaron

+0

Grazie, stavo cercando da anni di semplificare questo un po ' – Corone

+3

Hai letto http://stackoverflow.com/questions/13690184 - potrebbe essere correlato. – hadley

risposta

4

Questa non è una risposta, ma è troppo lungo per un commento

Il .Environment per la componente termini è identico per ogni modello risultante

e1 <- attr(fit[['V1']][[1]]$terms, '.Environment') 
e2 <- attr(fit[['V1']][[2]]$terms, '.Environment') 
e3 <- attr(fit[['V1']][[3]]$terms, '.Environment') 
identical(e1,e2) 
## TRUE 
identical(e2, e3) 
## TRUE 

sembra che data.table sta usando la stesso bit di memoria (mio termine non tecnico) per ogni valutazione di j per gruppo (che è efficiente). Tuttavia, quando viene chiamato update, lo utilizza per rimodellare il modello. Questo conterrà i valori dell'ultimo gruppo.

Quindi, se si fudge questo, funzionerà

fit = DT[, { xx <-list2env(copy(.SD)) 

      mymodel <-lm(Sepal.Length ~ Sepal.Width + Petal.Length) 
      attr(mymodel$terms, '.Environment') <- xx 
      list(list(mymodel))}, by= 'Species'] 





lfit2 <- fit[, list(list(update(V1[[1]], ~.-Sepal.Width))), by = Species] 
lfit2[,lapply(V1,nobs)] 
V1 V2 V3 
1: 41 39 42 
# using your exact diagnostic coding. 
lfit2[,nobs(V1[[1]]),by = Species] 
     Species V1 
1:  setosa 41 
2: versicolor 39 
3: virginica 42 

non una soluzione a lungo termine, ma almeno una soluzione.

Problemi correlati