2014-11-08 108 views
3

我正在嘗試創建一個庫。比方說,我有一個模型,我有一個輸出,輸入和描述函數的方程。投入將是:Julia:爲庫設置OOP模型的最佳方法是什麼

x= [1,2,3,4,5,6] 
y= [5,2,4,8,9,2] 

而且我把它變成一個功能:

#=returns y values=# 
function fit (x,a,b) 
    y=ax+b 
end 

,另一種是輸出總結使用描述函數:

#=Describes equation fitting=# 

function describe(#insert some model with data from the previous functions) 
    #=Prints the following: Residuals(y-fit(y)), x and y and r^2 
    a and b 

    =# 
end 

什麼是最好的方式在朱莉婭這樣做?我應該使用type嗎?

目前我使用一個非常大的功能,如:

function Model(x,y,a,b,describe ="yes") 
    ....function fit 
    ....Something with if statements to controls the outputs 
    ....function describe 
end 

但是,這是不是很有效,或者用戶友好。

+0

我不認爲我明白你正在嘗試做的。從'函數describe(m :: Model)'看起來你已經有了一個模型類型?最後一個函數是該類型的構造函數嗎? – spencerlyon2 2014-11-08 18:17:13

+0

@ spencerlyon2這只是僞代碼。讓我重寫它,所以它更清晰 – ccsv 2014-11-09 00:31:43

+0

@ spencerlyon2基本上我試圖找到一種方法來重寫一個函數,所以我不需要做類似'Model(1,2,4,5,「no」,「false 「...等)」,因此可以有單獨的命令來描述數據集,或對數據集執行不同的功能。 – ccsv 2014-11-09 00:38:10

回答

8

看起來好像你正試圖在Julia上特定的OOP風格,這並不是一個好的選擇。朱莉婭沒有課。而是使用類型,在這些類型上分派的函數和封裝整個模塊的組合。

作爲一個編制的例子讓我們做一個OLS迴歸的包。爲了封裝代碼,你將它包裝在一個模塊中。讓我們把它叫做OLSRegression

module OLSRegression 

end 

我們需要一個模型來存儲迴歸的結果,並派遣有關:

type OLS 
    a::Real 
    b::Real 
end 

然後,我們需要一個函數來滿足我們的OLS數據。而不是創造出自己的fit功能,我們可以延長一個可用的StatsBase.jl:

using StatsBase 

function StatsBase.fit(::Type{OLS}, x, y) 
    a, b = linreg(x, y) 
    OLS(a, b) 
end 

然後,我們可以創建一個describe功能,打印出的擬合模型:

function describe(obj::OLS) 
    println("The model fit is y = $(obj.a) + $(obj.b) * x") 
end 

最後,我們需要從模塊中導出創建類型和功能:

export OLS, describe, fit 

整個模塊放在一起是:

module OLSRegression 

using StatsBase 

export OLS, describe, fit 

type OLS <: RegressionModel 
    a::Real 
    b::Real 
end 

function StatsBase.fit(::Type{OLS}, x, y) 
    a, b = linreg(x, y) 
    OLS(a, b) 
end 

function describe(obj::OLS) 
    println("The model fit is y = $(obj.a) + $(obj.b) * x") 
end 

end 

你會再使用這樣的:

julia> using OLSRegression 

julia> m = fit(OLS, [1,2,5,4], [2,2,4,6]) 

julia> describe(m) 
The model fit is y = 1.1000000000000005 + 0.7999999999999999 * x 

編輯:我要補充的方法,多個調度和陰影一些意見。

在傳統的OOP語言中,您可以擁有具有相同名稱方法的不同對象。例如:我們有對象dog和對象cat。他們都有一個名爲run的方法。我可以用點語法調用適當的run方法:dog.run()cat.run()。這是單一派遣。根據第一個參數的類型調用適當的方法。由於第一個參數的重要性,它會出現在方法名稱之前,而不是在括號內。

在Julia這種調用方法的點語法,但它仍然有調度。相反,第一個參數與所有其他參數一樣出現在圓括號內。因此,您應該執行run(dog)run(cat),並且它仍會分派到dogcat類型的適當方法。

這也是describe(obj::OLS)的情況。我創建了一個新方法來描述並指定當第一個參數的類型爲OLS時應調用此方法。

朱莉婭的調度超越單派遣到多派遣。在單次調度中,調用cat.run("fast")cat.run(5)將調度到相同的方法,並且取決於使用不同類型的第二參數做不同事情的方法。在Julia run(cat, "fast")run(cat, 5)調度來分離方法。

我見過朱莉婭的創造者稱之爲動詞語言和傳統的OOP語言名詞語言。在名詞語言中,您將方法附加到對象(名詞),但在Julia中,您將方法附加到泛型函數(動詞)。在上面的模塊中,我同時創建了一個新的通用函數describe(因爲沒有該名稱的通用函數)並在其上附加了一個在OLS類型上分派的方法。

我與fit功能做的是什麼,而不是創建一個名爲fit我從StatsBase包導入並增加了對我們的擬合類型OLS的新方法,新的通用功能。現在我的fit方法和其他fit在其他包中的方法被調用時與參數的權限類型調用。我這樣做的原因是因爲如果我創建了一個新的擬合函數,它會在StatsBase中隱藏這個函數。對於在Julia中導出的函數,通常更好的方法是擴展現有的規範泛型函數,而不是創建自己的風險函數並在基礎或其他包中創建函數。

如果其他軟件包導出了自己的describe泛型函數,並且被加載到我們的OLSRegression軟件包後面,那麼將會使命令describe(m)發生錯誤。我們仍然可以使用完全限定名稱訪問我們的describe函數,即OLSRegression.describe

編輯2:關於::Type{OLS}的東西。

在函數調用fit(OLS, [1,2,5,4], [2,2,4,6])OLS被稱爲無括號,這意味着我沒有構建OLS類型的實例並通過對函數,而是我通過類型本身的方法。

obj::OLS::OLS部分指定對象應該是OLS類型的實例。在此之前的obj是我將該實例綁定到函數體中的名稱。 ::Type{OLS}在兩個方面有所不同。而不是指定的參數應該是類型OLS的實例,它指定該參數應該是的Type一個實例,具有OLS參數化。在冒號前沒有任何內容,因爲我沒有將它綁定到任何變量名,因爲我不需要在函數體中使用它。

的原因,我這樣做僅僅是爲了幫助fit不同方法之間的歧義。其他一些軟件包也可能會擴展StatsBase中的fit函數。如果我們都使用像StatsBase.fit(x, y)這樣的函數簽名,朱莉婭不知道分派哪個方法。相反,如果我用一個函數簽名像StatsBase.fit(::Type{OLS}, x, y)和其他包裝不喜歡的東西StatsBase.fit(::Type{NLLS}, x, y),那麼方法消除歧義,並且用戶可以通過類型指定他希望該法的第一個參數。

+0

因爲如何設置julia,我猜'function describe'只能用於'obj :: OLS',所以如果我有一個函數從另一個包描述,我會指出我正在使用這個'OLSRegression.describe() ' – ccsv 2014-11-09 20:09:14

+0

@ccsv我添加了一些評論,希望能夠清除它。 – 2014-11-11 18:51:37

+0

很好的答案。快速問題:爲什麼'.fit'函數需要放入':: Type {OLS}',但是爲了描述你放置了'obj :: OLS'?在後一種情況下,它的作用類似於調度的輸入過濾器,但我無法確定第一個語法的語法...... OLS實際上並不像輸入那樣工作。 – cd98 2014-11-15 15:45:05

1

Matlab傾向於鼓勵一個單一的函數,但在Julia中,將事情分解成小塊幾乎總是更好。我不確定我是否真的明白你想要做什麼,但對於文檔,請檢查DocileLexicon(它們是成對的)。

相關問題