2017-03-09 13 views
1

它是我第二天與朱莉婭學習和實驗。雖然我仔細閱讀了關於元編程的文檔(但也許不夠小心)和幾個相同的線程。我仍然無法弄清楚如何在函數內部使用它。 我tryed做一些數據更靈活的模擬如下功能:如何在函數參數中使用元編程?

using Distributions 
function gendata(N,NLATENT,NITEMS) 
    latent = repeat(rand(Normal(6,2),N,NLATENT), inner=(1,NITEMS)) 
    errors = rand(Normal(0,1),N,NLATENT*NITEMS) 
    x = latent+errors 
end 

通過這樣做:

using Distributions 
function gendata(N,NLATENT,NITEMS,LATENT_DIST="Normal(0,1)",ERRORS_DIST="Normal(0,1)") 
    to_eval_latent = parse("latent = repeat(rand($LATENT_DIST,N,NLATENT), inner=(1,NITEMS))") 
    eval(to_eval_latent) 
    to_eval_errors = parse("error = rand($ERRORS_DIST,N,NLATENT*NITEMS)") 
    eval(to_eval_errors) 
    x = latent+errors 
end 

但由於EVAL不要在局部範圍內工作,它不工作。我能做些什麼來圍繞這個工作?

也是原本的功能,似乎不是那麼快,我在性能上做了什麼大的失誤?

我真的appriciate任何recommandation。 在此先感謝。

+1

只是將分佈作爲參數傳遞有什麼問題?使用'eval'似乎過於複雜。 – phg

+0

@phg它似乎並不複雜,它是。代碼最初來自一個R腳本,這或多或少是必需的。你有什麼想法,爲什麼重複如此之慢?它是BLAS,因此它應該像閃電一樣快,它是功能中最慢的部分。 – AaronP

回答

5

不需要在那裏使用eval,通過將分佈類型作爲關鍵字args(或帶有默認值的命名參數)傳遞,您可以保持相同的靈活性。解析和評估「字符串型」參數通常會使優化失敗,應該避免。

function gendata(N,NLATENT,NITEMS; LATENT_DIST=Normal(0,1),ERRORS_DIST=Normal(0,1)) 
     latent = repeat(rand(LATENT_DIST,N,NLATENT), inner=(1,NITEMS)) 
     errors = rand(ERRORS_DIST,N,NLATENT*NITEMS) 
     x = latent+errors 
end 


julia> gendata(10,2,3, LATENT_DIST=Pareto(.3)) 
... 


julia> gendata(10,2,3, ERRORS_DIST=Gamma(.6)) 
... 

0

你不是真的要在這裏使用eval(慢,不會產生類型信息,將與編譯干擾等),但如果你想了解什麼出了問題,這裏是你會怎麼做:

無論它從代碼的其餘部分分開:

function gendata(N,NLATENT,NITEMS,LDIST_EX="Normal(0,1)",EDIST_EX="Normal(0,1)") 

    # Eval your expressions separately 

    LATENT_DIST = eval(parse(LDIST_EX)) 
    ERRORS_DIST = eval(parse(EDIST_EX)) 

    # Do your thing 

    latent = repeat(rand(LATENT_DIST,N,NLATENT), inner=(1,NITEMS)) 
    errors = rand(ERROR_DIST,N,NLATENT*NITEMS) 
    x = latent+errors  
end 

或者使用插補引用表達式:

function gendata(N,NLATENT,NITEMS,LDIST_EX="Normal(0,1)",EDIST_EX="Normal(0,1)") 

    # Obtain expression objects 

    LATENT_DIST = parse(LDIST_EX) 
    ERRORS_DIST = parse(EDIST_EX) 

    # Eval but interpolate in everything that's local to the function 
    # And you can't introduce local variables with eval so keep them 
    # out of it. 

    latent = eval(:(repeat(rand($LATENT_DIST,$N,$NLATENT), inner=(1,$NITEMS)))) 
    errors = eval(:(rand($ERRORS_DIST, $N, $NLATENT*$NITEMS))) 
    x = latent+errors 
end 

你也可以使用一個單一的eval使用let塊引入一個自包含的範圍:

function gendata(N,NLATENT,NITEMS,LDIST_EX="Normal(0,1)",EDIST_EX="Normal(0,1)") 

    LATENT_DIST = parse(LDIST_EX) 
    ERRORS_DIST = parse(EDIST_EX) 
    x = 
    @eval let 
    latent = repeat(rand($LATENT_DIST,$N,$NLATENT), inner=(1,$NITEMS)) 
    errors = (rand($ERRORS_DIST, $N, $NLATENT*$NITEMS)) 
    latent+errors 
    end 
end 

((@eval x) == eval(:(x)))

好吧,希望你能理解eval事情更好一點。第二天,我的意思是,你應該試驗;)

+0

非常感謝。非常有助於更好地理解「eval」。但是我會用previus答案的解決方案。這裏是我的解決方案,有點速度優化: 使用分佈 函數gendata(N,NLATENT,NITEMS; LATENT_DIST =正常(0,1),ERRORS_DIST =正常(0,1)) latent = repmat(rand(LATENT_DIST, N,NLATENT),1,NITEMS) 因爲我在eachindex(潛) 潛[i] =潛[I] +蘭特(ERRORS_DIST) 結束 潛 結束 – AaronP

+0

但有件事我真的不明白,在試圖優化性能的同時,使用repmat代替重複功能的速度提高了十倍,這是怎麼回事?兩者都是BLAS,來自Docs的線性代數部分。 – AaronP

+0

感謝您接受,但如果另一種解決方案更好,您應該接受,相反,這是更有意義的補充。 (雖然我是直接解決問題的人,但我認爲在這種情況下提出替代方案會更好) – phicr

相關問題