2010-12-06 41 views
2

La fonction suivante fonctionne, mais la dernière partie as.Date a été plus ou moins le résultat d'essais et d'erreurs qui ne comprennent pas complètement.Pourquoi dois-je régler de nouveau l'origine de as.Date après avoir utilisé ifelse? Y a-t-il un meilleur moyen?

### This function creates a real date column out of year/period that is saved in 
### in separate columns, plus it handles a 13th period in case of overlapping period 
### terminology. Turns quarters into months. 

realDate <- function (table,year="year_col",period="period_col"){ 


if (is.character(table) == TRUE) 
{ 
    dframe <- get(table) 
} 

else{ 
    dframe <- table 
} 


x <- expression({resDate <- with(dframe, 
        as.Date(paste(get(year),"-", 
            ifelse(get(period) > 9, get(period), 
              paste("0", get(period), sep = "")), 
            "-01", sep = ""))) 
     }) 

y <- expression({resDate <- with(dframe,as.Date(paste(get(year) + 1,"-","01","-01",sep="")))}) 

#### I do not get this? Why do I have to do this? 
a <- ifelse(get(period) == 13,eval(y),eval(x)) 
a <-as.Date(a, origin="1970-01-01") 


return(a) 

} 

Au lieu de cela j'ai essayé de le faire comme ça (parce qu'il était plus intuitive pour moi):

{ .... 
ifelse(get(period) == 13,eval(y),eval(x)) 
return(resDate) 
} 

Ce sont retournés les valeurs corrigées chaque fois que la condition était faux (pas) mais retourné NA si la la condition était VRAIE (oui). Pourquoi donc? Et si j'utilise la fonction ci-dessus, pourquoi dois-je redéfinir l'origine? Pourquoi j'ai encore appelé as.Date à nouveau?

EDIT:

a <- rep(2002:2010,2) 
b <- rep(1:13,2) 
d<-cbind(a,b[1:length(a)]) 
names(d) <- c("year_col","period_col") 

P.S .: J'ai trouvé ce thread sur ifelse vectorisé.

+0

donnant une idée sur l'entrée serait bien d'essayer certaines choses. –

+0

Cela fonctionne-t-il correctement si vous faites 'xx <-eval (x); yy <-eval (y); ifelse (get (période) == 13, yy, xx)'? – Marek

+0

désolé pour cela. J'ai édité mon post, vous pouvez cindier toute information à data.frame tant que les deux cols restent. –

Répondre

2

Votre construction est "intéressante" au moins. Pour commencer, ni x ni y ne donnent de résultat. Je me demande pourquoi vous utilisez une cession dans votre eval(). Cela vous donne un vecteur resDate qui est exactement ce que le dernier appel a été. Et cela ne dépend pas de la condition, c'est le dernier écrit (eval(x) dans votre cas). Ils sont exécutés avant l'exécution de la clause ifelse. De plus, la sortie que vous obtenez est la représentation numérique de vos données, pas l'objet de données. C'est dans resDate. Je suppose que ifelse ne peut pas déterminer la classe du vecteur de sortie que vous utilisez le eval() à l'intérieur. Je suis surpris que vous ayez une sortie, en fait, vous utilisez effectivement quelque chose qui pourrait être appelé un "bug" dans R (Microsoft l'appelle une fonctionnalité :-)). Votre erreur est dans votre ifelse: get(period) n'existe pas. il devrait être get(period, dframe). Alors ça marche. La seule raison pour laquelle cela fonctionne sur votre ordinateur, c'est parce que vous avez probablement un period dans votre espace de travail. Problème de classis lors du débogage.

En tout cas, je le ferais:

realDate <- function (table,year="year_col",period="period_col"){ 
    if (is.character(table)){ # is.character(table) returns a boolean already. 
     dframe <- get(table) 
    } else { 
     dframe <- table 
    } 
    year <- get(year,dframe) 
    period <- get(period,dframe) 

    year[period==13] <- year[period==13]+1 
    period[period==13] <- 1 

    as.Date(paste(year,"-",period,"-01",sep="")) 
} 

Ceci est un peu plus rapide que le vôtre, a moins de pièges et les conversions, et est plus le chemin R de le faire. Vous pouvez changer l'année [...] et la période [...] par des constructions ifelse, mais l'utilisation d'indices est généralement plus rapide.


EDIT:

Il est plus facile pour la génération de données:

dframe <- data.frame(
    year_col= rep(2006:2007,each=13), 
    period_col = rep(1:13,2) 
) 

realDate(dframe) 
[1] "2006-01-01" "2006-02-01" "2006-03-01" "2006-04-01" "2006-05-01" 
      "2006-06-01" "2006-07-01" "2006-08-01" "2006-09-01" 
[10] "2006-10-01" "2006-11-01" "2006-12-01" "2007-01-01" "2007-01-01" 
      "2007-02-01" "2007-03-01" "2007-04-01" "2007-05-01" 
[19] "2007-06-01" "2007-07-01" "2007-08-01" "2007-09-01" 
      "2007-10-01" "2007-11-01" "2007-12-01" "2008-01-01" 
+0

Sentez-vous libre de l'appeler étrange, ennuyeux, stoopid ... vous pouvez choisir. Bien qu'intéressant s'applique aussi, parce que j'ai beaucoup appris;). J'ai tendance à oublier que les cols ne sont pas la seule chose que vous pouvez indexer dans R. Thx aussi bien pour souligner l'erreur de débogage classique, bien sûr que vous aviez raison avec ça aussi. Ah, et ce # était sympa aussi ... tu as fait ma journée. Vraiment eu un problème majeur dans cette condition ... pourquoi get (période) ne fonctionne pas sans dframe? –

+1

@ ran2: c'est la même chose que d'appeler period_col dans votre espace de travail au lieu de dframe $ period_col. –

+1

+ Je tiens à souligner que le premier zéro (pour les périodes) n'était pas nécessaire lors de l'utilisation de as.Date(). –