2014-04-24 76 views
0

據我所知,eval(parse())速度慢,經常會導致調試問題。但是,有沒有適合或甚至有必要使用eval(parse())的情況?何時適合使用eval(parse())?

我有一個例子,下面我使用eval(parse())。我試圖解決一個ODE系統,其中模型定義是從用戶輸入設置的,並被粘貼在一個函數中,如diffeqns所示。參數是從包括解ODE的最優化步驟獲得的。因此,eval(parse())將被評估很多次。在這種情況下,我如何避免eval(parse())

library(deSolve) 

diffeqns <- structure(c("d_ParentW = - k_ParentW_to_sink * ParentW - k_ParentW_to_ParentS * ParentW - k_ParentW_to_MetW * ParentW + k_ParentS_to_ParentW * ParentS", 
         "d_ParentS = - k_ParentS_to_sink * ParentS + k_ParentW_to_ParentS * ParentW - k_ParentS_to_ParentW * ParentS - k_ParentS_to_MetS * ParentS", 
         "d_MetW = - k_MetW_to_sink * MetW + k_ParentW_to_MetW * ParentW - k_MetW_to_MetS * MetW + k_MetS_to_MetW * MetS", 
         "d_MetS = - k_MetS_to_sink * MetS + k_ParentS_to_MetS * ParentS + k_MetW_to_MetS * MetW - k_MetS_to_MetW * MetS" 
         ), .Names = c("ParentW", "ParentS", "MetW", "MetS")) 
mod_vars <- c("ParentW", "ParentS", "MetW", "MetS") 
odeini <- structure(c(103.5304, 0, 0, 0), .Names = c("ParentW", "ParentS", 
                "MetW", "MetS")) 
odeparms <- structure(c(0.0075920556751397, 109.831812097509, 0.00547432996880228, 
         0.067528800735385, 0.40912980024133, 0.512110576238725, 93.2375019578296, 
         1.48218125815231e-06, 312.228302990933, 255.11871122468), .Names = c("k_ParentW_to_sink", 
                          "k_ParentS_to_sink", "k_MetW_to_sink", "k_MetS_to_sink", "k_ParentW_to_ParentS", 
                          "k_ParentW_to_MetW", "k_ParentS_to_ParentW", "k_ParentS_to_MetS", 
                          "k_MetW_to_MetS", "k_MetS_to_MetW")) 

## experimenting Scripts for cleaner coding! 
DefDiff <- function(time, state, parms,mod_vars,diffeqns) { 
    ## an updated version of mkindiff 
    ## @example DefDiff(t,state,parms, mod_vars, diffeqns=mkinmodini$diffs) 

    diffs <- vector() 
    for (box in mod_vars) 
    { 
    diffname <- paste("d", box, sep="_") 
    diffs[diffname] <- with(as.list(c(time,state, parms)), 
          eval(parse(text=diffeqns[[box]]))) 
    } 
    ##https://stat.ethz.ch/pipermail/r-sig-dynamic-models/2010q2/000031.html 
    #bady <- (!is.finite(diffs))|(diffs<=0) 
    #diffs[bady] <- 0 
    return(list(c(diffs))) 
} 
diff1 <-function(time, state, parms){ 
    DefDiff(time, state, parms,mod_vars=mod_vars,diffeqns=diffeqns) 
    } 
outtimes <- seq(0,100,1) 
out <- ode(
    y = odeini, 
    times = outtimes, 
    func = diff1, 
    parms = odeparms) 
matplot(out) 

更新時間:

  1. 我試圖想如何使用substitue代替parse,但我擔心,我需要重寫,我已經寫使其真正大量的代碼工作。

  2. 這裏是link我再次認爲eval(parse())是難以避免的。

+0

你能指定它們在公式接口而不是字符串嗎? – Thomas

+0

@Thomas,我不確定我是否理解你的建議。對於簡單的情況,我可以寫'y〜Y_0 * exp(-k(t))'。但我不能寫下這個程序遇到的所有情況。 – Zhenglei

+0

或者我可以寫'y〜fo(P)'。但'fo()'又包含'eval(parse())'構造。 – Zhenglei

回答

-1

我對使用optim函數的優化過程有同樣的問題。

我的理解,fn論證該功能需要包括一個參數向量優化這樣的:

c(par[1], par[2], par[3]) # if there only 3 

所以,當大量的參數是alterates我創造下一個代碼得到這個矢量,只有指定數量則params的num_param

tmp_test_params <- NULL 

for (i in 1:num_param) tmp_test_params[[i]] <- paste ("par[",i,"]", sep = "") 

tmp_texto <- paste ("",tmp_test_params, collapse = ",") 
texto_param <- paste0 ("c(",tmp_texto,")") 

而不是使用eval (parse (text=texto_param))fn

在這種情況下,我沒有找到另一種方式。希望有人能幫助我回答你的問題。

0

我做了一個小實驗,測試用substitute代替parse可以獲得多少收益。使用下面的代碼我(慢)的計算機上得到的結果是:

> system.time(test1()) 
    user system elapsed 
275.38 0.11 314.78 
> system.time(test2()) 
    user system elapsed 
181.96 0.09 205.27 

我不知道這是否是在速度上顯著增益。或者我沒有正確使用substitute

下面的代碼改編自@ hadley的another answer

library(deSolve) 

diffeqns <- structure(c("d_ParentW = - k_ParentW_to_sink * ParentW - k_ParentW_to_ParentS * ParentW - k_ParentW_to_MetW * ParentW + k_ParentS_to_ParentW * ParentS", 
         "d_ParentS = - k_ParentS_to_sink * ParentS + k_ParentW_to_ParentS * ParentW - k_ParentS_to_ParentW * ParentS - k_ParentS_to_MetS * ParentS", 
         "d_MetW = - k_MetW_to_sink * MetW + k_ParentW_to_MetW * ParentW - k_MetW_to_MetS * MetW + k_MetS_to_MetW * MetS", 
         "d_MetS = - k_MetS_to_sink * MetS + k_ParentS_to_MetS * ParentS + k_MetW_to_MetS * MetW - k_MetS_to_MetW * MetS" 
         ), .Names = c("ParentW", "ParentS", "MetW", "MetS")) 
mod_vars <- c("ParentW", "ParentS", "MetW", "MetS") 
odeini <- structure(c(103.5304, 0, 0, 0), .Names = c("ParentW", "ParentS", 
                "MetW", "MetS")) 
odeparms <- structure(c(0.0075920556751397, 109.831812097509, 0.00547432996880228, 
         0.067528800735385, 0.40912980024133, 0.512110576238725, 93.2375019578296, 
         1.48218125815231e-06, 312.228302990933, 255.11871122468), .Names = c("k_ParentW_to_sink", 
                          "k_ParentS_to_sink", "k_MetW_to_sink", "k_MetS_to_sink", "k_ParentW_to_ParentS", 
                          "k_ParentW_to_MetW", "k_ParentS_to_ParentW", "k_ParentS_to_MetS", 
                          "k_MetW_to_MetS", "k_MetS_to_MetW")) 

## experimenting Scripts for cleaner coding! 
DefDiff <- function(time, state, parms,mod_vars,diffeqns) { 
    ## an updated version of mkindiff 
    ## @example DefDiff(t,state,parms, mod_vars, diffeqns=mkinmodini$diffs) 

    diffs <- vector() 
    for (box in mod_vars) 
    { 
    diffname <- paste("d", box, sep="_") 
    diffs[diffname] <- with(as.list(c(time,state, parms)), 
          eval(parse(text=diffeqns[[box]]))) 
    } 
    ##https://stat.ethz.ch/pipermail/r-sig-dynamic-models/2010q2/000031.html 
    #bady <- (!is.finite(diffs))|(diffs<=0) 
    #diffs[bady] <- 0 
    return(list(c(diffs))) 
} 
diff1 <-function(time, state, parms){ 
    DefDiff(time, state, parms,mod_vars=mod_vars,diffeqns=diffeqns) 
    } 
outtimes <- seq(0,100,1) 

diffsub <- function(time,state,parms){ 
    diffs <- vector() 
    diffexps <- Defdiff2(odeparms=parms,odeini=state,time=time) 
    for (box in mod_vars) 
    { 
    diffname <- paste("d", box, sep="_") 
    diffs[diffname] <-eval(diffexps[[box]]) 
    } 
    return(list(c(diffs))) 
} 

## some functions to work out the expressions: 
add_expr_1 <- function(x, y) { 
    substitute(x + y, list(x = x, y = y)) 
} 
add_expr <- function(x) Reduce(add_expr_1, x) 
substitute_q <- function(x, env) { 
    call <- substitute(substitute(y, env), list(y = x)) 
    eval(call) 
} 
neg_exp <- function(exp){ 
    ## example: neg_exp(neg_exp(1)) 
    substitute(-1*x,list(x=exp)) 
} 
one_parent <- function(type,par,ini,t=0){ 
    if(type=="SFO"){ 
    rhs <- substitute(-k*M,list(k=par,M=ini)) 
    }else if(type=="DFOP"){ 
     rhs <- substitute(-(k1*g*exp(-k1*t)+k2*(1-g)*exp(-k2*t))/(g*exp(-k1*t)+(1-g)*exp(-k2*t))*M,list(k1=par[1],k2=par[2],g=par[3],M=ini,t=t)) 
    }else if(type=="FOMC"){ 
    rhs <- substitute(-alpha/beta*M/(t/beta+1),list(alpha=par[1],beta=par[2],M=ini,t=t)) 
    }else if(type=="HS"){ 
    rhs <- substitute(ifelse(t<=tb, -k1*M,-k2*M),list(k1=par[1],k2=par[2],tb=par[3],M=ini,t=t)) 
    }else{ 
    rhs <- NULL 
    } 
    rhs 
} 

Defdiff2 <- function(odeparms,odeini,time){ 
diffexps <- list() 
diffexps[["ParentW"]] <- add_expr(list(
    one_parent("SFO",par=odeparms["k_ParentW_to_sink"],ini=odeini[["ParentW"]]), 
    one_parent("SFO",par=odeparms["k_ParentW_to_MetW"],ini=odeini[["ParentW"]]), 
    one_parent("SFO",par=odeparms["k_ParentW_to_ParentS"],ini=odeini[["ParentW"]]), 
    neg_exp(one_parent("SFO",par=odeparms["k_ParentS_to_ParentW"],ini=odeini[["ParentS"]])) 
)) 
diffexps[["ParentS"]] <- add_expr(list(
    one_parent("SFO",par=odeparms["k_ParentS_to_sink"],ini=odeini[["ParentS"]]), 
    one_parent("SFO",par=odeparms["k_ParentS_to_MetS"],ini=odeini[["ParentS"]]), 
    one_parent("SFO",par=odeparms["k_ParentS_to_ParentW"],ini=odeini[["ParentS"]]), 
    neg_exp(one_parent("SFO",par=odeparms["k_ParentW_to_ParentS"],ini=odeini[["ParentW"]])) 
)) 
diffexps[["MetW"]] <- add_expr(list(
    one_parent("SFO",par=odeparms["k_MetW_to_sink"],ini=odeini[["MetW"]]), 
    one_parent("SFO",par=odeparms["k_MetW_to_MetS"],ini=odeini[["MetW"]]), 
    neg_exp(one_parent("SFO",par=odeparms["k_ParentW_to_MetW"],ini=odeini[["ParentW"]])), 
    neg_exp(one_parent("SFO",par=odeparms["k_MetS_to_MetW"],ini=odeini[["MetS"]])) 
)) 
diffexps[["MetS"]] <- add_expr(list(
    one_parent("SFO",par=odeparms["k_MetS_to_sink"],ini=odeini[["MetS"]]), 
    neg_exp(one_parent("SFO",par=odeparms["k_MetW_to_MetS"],ini=odeini[["MetW"]])), 
    one_parent("SFO",par=odeparms["k_MetS_to_MetW"],ini=odeini[["MetS"]]), 
    neg_exp(one_parent("SFO",par=odeparms["k_ParentS_to_MetS"],ini=odeini[["ParentS"]])) 
)) 
return(diffexps) 
} 
test1 <- function(){ 
    for(i in 1:1000){ 
    out <- ode(
     y = odeini, 
     times = outtimes, 
     func = diff1, 
     parms = odeparms) 
    } 
    } 
test2 <- function(){ 
    for(i in 1:1000){ 
    out <- ode(
     y = odeini, 
     times = outtimes, 
     func = diffsub, 
     parms = odeparms) 
    } 
    } 
system.time(test1()) 
system.time(test2())