Pourquoi ne retourne sapply une matrice que je dois transposer, puis la matrice transposée ne se fixe pas à une trame de données?

StackOverflow https://stackoverflow.com/questions/4140371

Question

Je vous serais reconnaissant de comprendre pourquoi cela se produit et comment je pourrais le faire avec plus d'éloquence.

Quand j'utilise sapply, je voudrais revenir à une matrice de 3x2, mais il renvoie une matrice 2x3. Pourquoi est-ce? Et pourquoi est-il difficile de le joindre à une autre trame de données?

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

quand je tente de joindre ces derniers,

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

L'erreur que je reçois est:

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

même si celle-ci apparaît pour donner le résultat souhaité:

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

Je ne peux pas fonctionner sur les variables:

b$var1/b$var2

retourne

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

Merci!

Était-ce utile?

La solution

Pour développer la réponse de dwin: il serait utile d'examiner la structure de votre objet out. Il explique pourquoi b$var1/b$var2 ne fait pas ce que vous attendez.

> 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 famille apply des fonctions sont conçus pour fonctionner sur des vecteurs et des réseaux, de sorte que vous devez prendre soin lors de leur utilisation avec data.frames (qui sont généralement des listes de vecteurs). Vous pouvez utiliser le fait que data.frames sont des listes à votre avantage avec 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

Autres conseils

D'abord un peu de notation R. Le Si vous regardez le code pour sapply, vous trouverez la réponse à votre question. Les contrôles de la fonction sapply pour voir si la longueur de la liste sont tous égaux, et si oui, d'abord « unlist () » sont eux et prend alors cette série de listes comme argument de données à array(). Depuis array (comme matrice ()) par défaut ses valeurs dans organise la colonne principale ordre, c'est ce que vous obtenez. Les listes sont tournées de leur côté. Si vous ne l'aimez pas, vous pouvez définir une nouvelle tsapply fonction qui renvoie les valeurs transposés:

> 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 

... une matrice 3 x 2.

Jetez un oeil à ddply du paquet 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
})
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top