2010-11-10 3 views
5

Gradirei approfondire perché questo accade e come potrei farlo in modo più eloquente.Perché restituisce saggiamente una matrice che devo trasporre, e quindi la matrice trasposta non si collegherà a un dataframe?

Quando uso saply, mi piacerebbe che restituisse una matrice 3x2, ma restituisce una matrice 2x3. Perchè è questo? E perché è difficile collegarlo a un altro frame di dati?

a <- data.frame(id=c('a','b','c'), var1 = c(1,2,3), var2 = c(3,2,1)) 
out <- sapply(a$id, function(x) out = a[x, c('var1', 'var2')]) 
#out is 3x2, but I would like it to be 2x3 
#I then want to append t(out) (out as a 2x3 matrix) to b, a 1x3 dataframe 
b <- data.frame(var3=c(0,0,0)) 

quando provo a collegare questi,

b[,c('col2','col3')] <- t(out) 

L'errore che ottengo è:

Warning message: 
In `[<-.data.frame`(`*tmp*`, , c("col2", "col3"), value = list(1, : 
    provided 6 variables to replace 2 variables 

anche se la seguente sembra dare il risultato desiderato:

rownames(out) <- c('col1', 'col2') 
b <- cbind(b, t(out)) 

Non posso operare su variabili e:

b$var1/b$var2 

restituisce

Error in b$var1/b$var2 : non-numeric argument to binary operator 

Grazie!

+1

Cosa stai cercando di fare con questi dati? Il tuo esempio in realtà non fa nulla di significativo. – hadley

+2

@hadley: l'esempio segue le linee guida sulla pubblicazione di R per fornire un esempio minimo e praticabile. Il caso reale è piuttosto complesso e la complessità sottrarrebbe alla domanda centrale. La funzione che ho stima la sensibilità di un modello a 20 parametri diversi utilizzando un'espansione di serie Taylor e accetta un dataframe 20x8 come input. Sarei felice di inviare un esempio completo riproducibile se lo desideri, anche se non è ancora pronto per essere reso pubblico. –

+1

Devi cercare un mezzo felice tra qualcosa che sia facile da capire e qualcosa che catturi l'essenza del problema con cui stai lottando.Nel tuo esempio attuale sembra che tu stia cercando di ottenere che 'b' sia uguale a' a'. – hadley

risposta

3

Per espandere la risposta di DWin: sarebbe utile esaminare la struttura dell'oggetto out. Spiega perché b$var1/b$var2 non fa quello che ti aspetti.

> out <- sapply(a$id, function(x) out = a[x, c('var1', 'var2')]) 
> str(out) # this isn't a data.frame or a matrix... 
List of 6 
$ : num 1 
$ : num 3 
$ : num 2 
$ : num 2 
$ : num 3 
$ : num 1 
- attr(*, "dim")= int [1:2] 2 3 
- attr(*, "dimnames")=List of 2 
    ..$ : chr [1:2] "var1" "var2" 
    ..$ : NULL 

La apply famiglia di funzioni sono progettati per lavorare su vettori e matrici, quindi è necessario fare attenzione quando li utilizzano con data.frames (che di solito sono gli elenchi dei vettori). Puoi usare il fatto che data.frames sono liste a tuo vantaggio con lapply.

> out <- lapply(a$id, function(x) a[x, c('var1', 'var2')]) # list of data.frames 
> out <- do.call(rbind, out) # data.frame 
> b <- cbind(b,out) 
> str(b) 
'data.frame': 3 obs. of 4 variables: 
$ var3: num 0 0 0 
$ var1: num 1 2 3 
$ var2: num 3 2 1 
$ var3: num 0 0 0 
> b$var1/b$var2 
[1] 0.3333333 1.0000000 3.0000000 
2

Prima un po 'di notazione R. Se guardi il codice per sdolcinato, troverai la risposta alla tua domanda. La funzione sapply controlla se le lunghezze delle liste sono tutte uguali e, in tal caso, prima le elenca "unlist()" e poi prende quella serie di liste come argomento dati su array(). Poiché l'array (come matrix()) di default dispone i suoi valori nell'ordine delle colonne, questo è ciò che ottieni. Le liste si girano dalla loro parte. Se non ti piace, allora si può definire una nuova funzione tsapply che restituirà i valori recepite:

> tsapply <- function(...) t(sapply(...)) 
> out <- tsapply(a$id, function(x) out = a[x, c('var1', 'var2')]) 
> out 
    var1 var2 
[1,] 1 3 
[2,] 2 2 
[3,] 3 1 

... una matrice 3 x 2.

+1

Tecnicamente, 'out' non è una matrice. È una lista con gli attributi 'dim' e' dimnames'. Per esempio. 'out% *% t (out)' fallisce. –

+0

Tranne che R pensa che sia una matrice:> is.matrix (out) [1] TRUE –

1

Dai un'occhiata alla ddply dal pacchetto plyr

a <- data.frame(id=c('a','b','c'), var1 = c(1,2,3), var2 = c(3,2,1)) 

library(plyr) 
ddply(a, "id", function(x){ 
    out <- cbind(O1 = rnorm(nrow(x), x$var1), O2 = runif(nrow(x))) 
    out 
})