Pourquoi ne retourne sapply une matrice que je dois transposer, puis la matrice transposée ne se fixe pas à une trame de données?
-
30-09-2019 - |
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!
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
})