2010-09-22 36 views
6

J'ai essayé d'utiliser acast de reshape2 dans une fonction auto-écrite, mais j'ai eu le problème qu'acast n'a pas trouvé les données que je lui ai envoyées.Comment utiliser acast (reshape2) dans une fonction dans R?

Voici mes données:

library("reshape2") 
x <- data.frame(1:3, rnorm(3), rnorm(3), rnorm(3))  
colnames(x) <- c("id", "var1", "var2", "var3") 
y <-melt(x, id = "id", measure = c("var1", "var2", "var3")) 

y ressemble alors à ceci:

id variable  value 
1 1  var1 0.1560812 
2 2  var1 1.0343844 
3 3  var1 -1.4157728 
4 1  var2 0.8808935 
5 2  var2 0.1719239 
6 3  var2 0.6723758 
7 1  var3 -0.7589631 
8 2  var3 1.1325995 
9 3  var3 -1.5744876 

maintenant je peux le jeter en arrière par l'intermédiaire acast:

> acast(y,y[,1] ~ y[,2]) 
     var1  var2  var3 
1 0.1560812 0.8808935 -0.7589631 
2 1.0343844 0.1719239 1.1325995 
3 -1.4157728 0.6723758 -1.5744876 

Cependant, lors de la rédaction d'un petit emballage pour acast qui devrait faire la même chose, je reçois un stupide messages d'erreur:

wrap.acast <- function(dat, v1 = 1, v2 = 2) { 
    out <- acast(dat, dat[,v1] ~ dat[,v2]) 
    return(out) 
} 

wrap.acast(y) 

Error in eval(expr, envir, enclos) : object 'dat' not found 

Le problème est évidemment lié à quelque chose comme des environnements et des variables globales/locales. Comme il donne d'autres messages d'erreur après avoir déclaré dat dans l'environnement global (c'est-à-dire, v1 et v2 pas trouvé tant qu'ils ne sont pas globaux).

Je voudrais utiliser resahpe (en particulier acast) dans une fonction sans avoir à déclarer les variables en dehors de la fonction. Quel est le truc?

Merci.

+0

C'est un problème qui survient plus souvent ces derniers temps. Au départ, je trouvais que c'était un problème avec les méthodes S4, mais apparemment, cela peut aussi se produire avec d'autres fonctions. Ceci est censé être un bug dans R, voir aussi les réponses à cette question: http://stackoverflow.com/questions/3574858/values-not-being-copied-to-the-next-local-environment/ –

+0

Merci Joris. Mais maintenant j'ai l'impression qu'il n'y a pas de solution facile à mon problème. pas trop gentil ... – Henrik

+0

On vient de le découvrir il y en a un en fait. C'est une question de typage correct. –

Répondre

5

Au lieu d'utiliser la spécification de la formule, utilisez la spécification de caractères:

acast(y, list(names(y)[1], names(y)[2])) 
+0

C'est encore plus simple. Merci beaucoup. Et encore plus merci de fournir reshape2 et tous vos super paquets! – Henrik

2

Correction: le problème n'est pas qu'il ne trouve pas de dat, mais qu'il ne trouve pas dat [, v1] et dat [, v2] dans la formule spécifiée. Acast prend un argument de la formule type, et celui-ci est évalué dans un environnement temporaire créé autour de votre trame de données. Dans cet environnement, il ne trouve pas d'objet "dat" lorsque la fonction est enveloppée dans un autre.

Je ne suis pas complètement à la recherche de comment cela fonctionne dans le global et ne le fait pas quand il est emballé, mais si vous alimentez une formule, elle fonctionne également dans une fonction.

wrap.acast <- function(dat, v1 = 1, v2 = 2) { 
    x1 <- names(dat)[v1] 
    x2 <- names(dat)[v2] 
    form <- as.formula(paste(x1,"~",x2)) 
    out <- acast(dat,form) 
    return(out) 
} 

en utilisant vos données de jouets:

> wrap.acast(y) 
     var1  var2  var3 
1 0.04095337 0.4044572 -0.4532233 
2 1.23905358 1.2493187 0.7083557 
3 0.72798307 0.7868746 1.7144811 
+0

C'est ce que je voulais. Merci beaucoup. – Henrik

-2

J'ai trouvé une façon assez inélégante pour résoudre le problème en utilisant les affectations super (<<-).
La fonction est remplacée par la suivante. Mais, c'est plutôt moche car cela crée des variables globales qui restent.

wrap.acast <- function(dat, v1 = 1, v2 = 2) { 
    dat <<- dat 
    v1 <<- v1 
    v2 <<- v2 
    out <- acast(dat, dat[,v1] ~ dat[,v2]) 
    return(out) 
} 

Je suis toujours très intéressé par d'autres solutions (moins colmatantes).

avant d'exécuter la fonction:

> ls() 
[1] "wrap.acast" "x"   "y"  

après l'exécution de la fonction:

> ls() 
[1] "dat"  "v1"   "v2"   "wrap.acast" "x"   
[6] "y" 
+0

Comme vous l'avez remarqué vous-même, l'utilisation de super-affectations doit être évitée à tout moment, sauf si vous voulez vraiment faire une variable globale. Et même alors, vous voudrez peut-être repenser le problème ... –

4

Une question est que vous abusez de la notation de formule dans R. Vous ne devriez pas faire des choses comme

> acast(y, y[,1] ~ y[,2]) 
     var1  var2   var3 
1 2.1726117 0.6107264 0.291446236 
2 0.4755095 -0.9340976 -0.443291873 
3 -0.7099464 -1.2536334 0.001105352 

car les bits 'y' sont redondants si un objet de données est fourni. Si vous faites référence aux variables y par nom directement dans la formule, les choses fonctionnent bien

> acast(y, id ~ variable) 
     var1  var2   var3 
1 2.1726117 0.6107264 0.291446236 
2 0.4755095 -0.9340976 -0.443291873 
3 -0.7099464 -1.2536334 0.001105352 

et le code est beaucoup plus facile à lire dans cette deuxième version. Faire ce que vous voulez en utilisant l'emballage acast va impliquer de générer la formule correcte en utilisant le names, comme le souligne Joris, et la solution de Hadley est beaucoup plus simple. Donc, mon point est vraiment de faire attention à la façon dont vous utilisez la spécification de formule dans R. Vous vous épargnerez beaucoup de problèmes à long terme (mais pas spécifiquement avec ce problème particulier) si vous utilisez des formules correctement.