2010-09-29 4 views
0

Как я могу написать все это в одной строке?Упростить ave() или aggregate() с несколькими входами

mydata является "zoo" серии, предел числовой вектор того же размера

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

Кажется, что эта процедура накладывает внутридневной стоп-лосс на основе maxdrawdown. Поэтому я предполагаю, что вы хотите иметь возможность передавать переменный предел в качестве второго аргумента своей функции агрегации, которая только в настоящее время использует только 1 функцию из-за того, как работает ave.

Если все это в одной строке не является абсолютной необходимостью, я могу использовать функцию, которую я написал, которая обобщает агрегацию через «режущие переменные». Вот код:

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 как строка
  • имя переменной во входном d ata.frame, которые являются входами в функцию

Если вы посмотрите на кишки функции «mtapplylist2», ключевые компоненты будут «разделены» и «сопоставить». Эти функции достаточно быстры (я думаю, что split реализован на C).

Это работает с функциями, требующими нескольких аргументов, а также для функций, возвращающих вектор того же размера или агрегированного значения.

Попробуйте и дайте мне знать, если это решит вашу проблему.

+0

Здравствуйте. Я попробую. благодаря – skan