2010-09-29 5 views
0

Comment écrire tout cela sur une ligne?Simplifier ave() ou aggregate() avec plusieurs entrées

mydata est une série "zoo", limite est un vecteur numérique de la même taille

tmp <- ave(coredata(mydata), as.Date(index(mydata)), 
      FUN = function(x) cummax(x)-x) 
tmp <- (tmp < limit) 
final <- ave(tmp, as.Date(index(mydata)), 
      FUN = function(x) cumprod(x)) 

J'ai essayé d'utiliser deux vecteurs comme argument pour ave(...) mais il semble juste accepter un même si je les rejoins dans une matrice.

Ceci est juste un exemple, mais toute autre fonction pourrait être utilisée.

Ici, j'ai besoin de comparer la valeur de cummax(mydata)-mydata avec un vecteur numérique et une fois qu'il le dépasse Je vais garder les zéros jusqu'à la fin de la journée. Le cummax est calculé à partir du début de chaque jour.

Si la limite était un numéro unique au lieu d'un vecteur (avec des nombres différents possibles) Je pourrais écrire:

ave(coredata(mydata), as.Date(index(mydata)), 
    FUN = function(x) cumprod((cummax(x) - x) < limit)) 

Mais je ne peux pas y introduire un vecteur plus que x (il devrait avoir le même longueur que chaque jour) et je ne sais pas comment l'introduire comme un autre argument dans ave().

Répondre

1

On dirait que cette routine impose un stop-stop intraday basé sur maxdrawdown. Donc je suppose que vous voulez pouvoir passer en limite variable comme deuxième argument à votre fonction d'agrégation qui ne prend actuellement qu'une seule fonction en raison de la façon dont ave fonctionne.

Si mettre tout cela en une ligne n'est pas un must absolu, je peux partager une fonction que j'ai écrite qui généralise l'agrégation via "couper les variables". Voici le code:

mtapplylist2 <- function(t, IDX, DEF, MoreArgs=NULL, ...) 
{ 
    if(mode(DEF) != "list") 
    { 
    cat("Definition must be list type\n"); 
    return(NULL); 
    } 

    a  <- c(); 
    colnames <- names(DEF); 
    for (i in 1:length(DEF)) 
    { 
    def <- DEF[[i]]; 
    func <- def[1]; 
    if(mode(func) == "character") { func <- get(func); } 
    cols <- def[-1]; 

    # build the argument to be called 
    arglist  <- list(); 
    arglist[[1]] <- func; 
    for(j in 1:length(cols)) 
    { 
     col <- cols[j]; 
     grp <- split(t[,col], IDX); 
     arglist[[1+j]] <- grp; 
    } 
    arglist[["MoreArgs"]] <- MoreArgs; 
    v <- do.call("mapply", arglist); 
    # print(class(v)); print(v); 
    if(class(v) == "matrix") 
    { 
     a <- cbind(a, as.vector(v)); 
    } else { 
     a <- cbind(a, v); 
    } 
    } 
    colnames(a) <- colnames; 
    return(a); 
} 

Et vous pouvez l'utiliser comme ceci:

# assuming you have the data in the data.frame 
df <- data.frame(date=rep(1:10,10), ret=rnorm(100), limit=rep(c(0.25,0.50),50)) 

dfunc <- function(x, ...) { return(cummax(x)-x) } 
pfunc <- function(x,y, ...) { return((cummax(x)-x) < y) } 

# assumes you have the function declared in the same namespace 
def <- list(
"drawdown" = c("dfunc", "ret"), 
"hasdrawdown" = c("pfunc", "ret", "limit") 
); 

# from R console 
> def <- list("drawdown" = c("dfunc", "ret"),"happened" = c("pfunc","ret","limit")) 
> dim(mtapplylist2(df, df$date, def)) 
[1] 100 2 

Notez que la variable "def" est une liste contenant les éléments suivants:

  • Nom de la colonne calculée
  • nom de la fonction d'argument vecteur sous forme de chaîne
  • nom de la variable dans l'entrée d ata.frame qui sont des entrées dans la fonction

Si vous regardez les entrailles de la fonction "mtapplylist2", les composants clés seraient "split" et "mapply". Ces fonctions sont suffisamment rapides (je pense que split est implémenté en C).

Ceci fonctionne avec des fonctions nécessitant plusieurs arguments, et aussi pour des fonctions retournant un vecteur de même taille ou de valeur agrégée.

Essayez-le et faites le moi savoir si cela résout votre problème.

+0

Bonjour. Je vais l'essayer. Merci – skan

Questions connexes