40 votes

Erreur d'objet non trouvé avec ddply à l'intérieur d'une fonction

Cela a vraiment mis au défi ma capacité à déboguer du code R.

Je veux utiliser ddply() pour appliquer les mêmes fonctions à différentes colonnes nommées de manière séquentielle, par exemple a, b, c. Pour ce faire, j'ai l'intention de transmettre de manière répétée le nom de la colonne sous forme de chaîne et d'utiliser la fonction eval(parse(text=ColName)) pour permettre à la fonction de le référencer. J'ai récupéré cette technique dans une autre réponse.

Et cela fonctionne bien, jusqu'à ce que je mette ddply() à l'intérieur d'une autre fonction. Voici l'exemple de code :

# Required packages:
library(plyr)

myFunction <- function(x, y){
    NewColName = "a"
    z = ddply(x, y, summarize,
            Ave = mean(eval(parse(text=NewColName)), na.rm=TRUE)
    )
    return(z)
}

a = c(1,2,3,4)
b = c(0,0,1,1)
c = c(5,6,7,8)
df = data.frame(a,b,c)
sv = c("b")

#This works.
ColName = "a"
ddply(df, sv, summarize,
        Ave = mean(eval(parse(text=ColName)), na.rm=TRUE)
)

#This doesn't work
#Produces error: "Error in parse(text = NewColName) : object 'NewColName' not found"
myFunction(df,sv)

#Output in both cases should be
#  b Ave
#1 0 1.5
#2 1 3.5

Des idées ? NewColName est même défini à l'intérieur de la fonction !

Je pensais que la réponse à cette question, loops-to-create-new-variables-in-ddply Il pourrait m'aider, mais j'ai assez tapé sur la tête pour aujourd'hui et il est temps de lever la main et de demander de l'aide.

22voto

Peter O Points 331

La solution d'aujourd'hui à cette question consiste à faire summarize en here(summarize) . par exemple

myFunction <- function(x, y){
    NewColName = "a"
    z = ddply(x, y, here(summarize),
            Ave = mean(eval(parse(text=NewColName)), na.rm=TRUE)
    )
    return(z)
}

here(f) ajouté au plyr en décembre 2012, capture le contexte actuel.

14voto

James Points 24725

Vous pouvez y parvenir en combinant do.call y call pour construire l'appel dans un environnement où NewColName est toujours visible :

myFunction <- function(x,y){
NewColName <- "a"
z <- do.call("ddply",list(x, y, summarize, Ave = call("mean",as.symbol(NewColName),na.rm=TRUE)))
return(z)
}

myFunction(d.f,sv)
  b Ave
1 0 1.5
2 1 3.5

9voto

joran Points 68079

Je rencontre parfois des problèmes de ce genre lorsque je combine ddply avec summarize o transform ou quelque chose comme ça et, n'étant pas assez intelligent pour deviner les tenants et aboutissants de la navigation dans divers environnements, j'ai tendance à contourner le problème en n'utilisant tout simplement pas l'option summarize et utiliser à la place ma propre fonction anonyme :

myFunction <- function(x, y){
    NewColName <- "a"
    z <- ddply(x, y, .fun = function(xx,col){
                             c(Ave = mean(xx[,col],na.rm=TRUE))}, 
               NewColName)
    return(z)
}

myFunction(df,sv)

Évidemment, le fait d'effectuer ces opérations "manuellement" a un coût, mais cela permet souvent d'éviter le casse-tête que représentent les problèmes d'évaluation liés à la combinaison de plusieurs éléments. ddply y summarize . Cela ne veut pas dire, bien sûr, que Hadley ne viendra pas avec une solution...

4voto

Joris Meys Points 38980

Le problème se situe dans le code du paquet plyr lui-même. Dans la fonction summarize, il y a une ligne eval(substitute(...),.data,parent.frame()) . Il est bien connu que parent.frame() peut faire des choses plutôt funky et inattendues. T

La solution de @James est une très bonne solution de contournement, mais si je me souviens bien, @Hadley lui-même a dit auparavant que le paquet plyr n'était pas destiné à être utilisé dans les fonctions.

Désolé, je me suis trompé. On sait cependant que pour le moment, le paquet plyr pose des problèmes dans ces situations.

Par conséquent, je vous donne une solution de base pour le problème :

myFunction <- function(x, y){
    NewColName = "a"
    z = aggregate(x[NewColName],x[y],mean,na.rm=TRUE)
    return(z)
}
> myFunction(df,sv)
  b   a
1 0 1.5
2 1 3.5

3voto

Ari B. Friedman Points 24940

On dirait que vous avez un problème d'environnement. L'affectation globale résout le problème, mais au prix de l'âme :

library(plyr)

a = c(1,2,3,4)
b = c(0,0,1,1)
c = c(5,6,7,8)
d.f = data.frame(a,b,c)
sv = c("b")

ColName = "a"
ddply(d.f, sv, summarize,
        Ave = mean(eval(parse(text=ColName)), na.rm=TRUE)
)

myFunction <- function(x, y){
    NewColName <<- "a"
    z = ddply(x, y, summarize,
            Ave = mean(eval(parse(text=NewColName)), na.rm=TRUE)
    )
    return(z)
}

myFunction(x=d.f,y=sv)

eval cherche dans parent.frame(1). Donc, si vous définissez plutôt NewColName en dehors de MyFunction, cela devrait fonctionner :

rm(NewColName)
NewColName <- "a"
myFunction <- function(x, y){

    z = ddply(x, y, summarize,
            Ave = mean(eval(parse(text=NewColName)), na.rm=TRUE)
    )
    return(z)
}
myFunction(x=d.f,y=sv)

En utilisant get pour extraire my.parse de l'environnement précédent, nous pouvons nous rapprocher, mais nous devons toujours passer curenv comme un global :

myFunction <- function(x, y){
    NewColName <- "a"
    my.parse <- parse(text=NewColName)
    print(my.parse)
    curenv <<- environment()
    print(curenv)

    z = ddply(x, y, summarize,
            Ave = mean( eval( get("my.parse" , envir=curenv ) ), na.rm=TRUE)
    )
    return(z)
}

> myFunction(x=d.f,y=sv)
expression(a)
<environment: 0x0275a9b4>
  b Ave
1 0 1.5
2 1 3.5

Je soupçonne que ddply est déjà évaluée dans le .GlobalEnv, ce qui explique pourquoi toutes les commandes parent.frame() y sys.frame()

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X