代码之家  ›  专栏  ›  技术社区  ›  skan

使用多个输入简化ave()或aggregate()

  •  0
  • skan  · 技术社区  · 15 年前

    我怎么能把这些都写在一行呢?

    mydata 是一个 "zoo" 级数,limit是相同大小的数值向量

    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))
    

    我试着用两个向量作为参数 ave(...) 但即使我把它们加入矩阵,它似乎也只接受一个。

    这只是一个例子,但是可以使用任何其他函数。

    在这里我需要比较 cummax(mydata)-mydata 带数值向量和 一旦它超过它,我会保持零直到一天结束。这个 cummax 从每天开始计算。

    如果极限是一个数字而不是一个向量(可能有不同的数字),我可以写它:

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

    但是我不能在这里引入向量 x (应该和每天一样长)我不知道如何把它作为 ave() .

    1 回复  |  直到 13 年前
        1
  •  1
  •   jbremnant    15 年前

    似乎这个程序会根据最大提取额来进行日内止损。因此,我假设您希望能够将变量limit作为第二个参数传递给聚合函数,由于ave的工作方式,聚合函数目前只接受1个函数。

    如果将所有这些放在一行并不是绝对必须的,我可以共享一个我编写的通过“剪切变量”泛化聚合的函数。代码如下:

    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);
    }
    

    你可以这样使用它:

    # 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
    

    请注意,“def”变量是包含以下项的列表:

    • 计算列名
    • 向量arg函数名作为字符串
    • 输入函数的input data.frame中变量的名称

    如果你看看“mtapplylist2”函数的核心,关键组件将是“split”和“mapply”。这些函数足够快(我认为split是用C实现的)。

    这适用于需要多个参数的函数,也适用于返回相同大小或聚合值的向量的函数。

    试试看,让我知道这是否能解决你的问题。