2012-02-28 51 views
5

首先,這個問題不是試圖解決特定的問題。作爲R的新手,我也在努力創建更高效​​的代碼和代碼構建過程。獲得對不同編程方法甚至風格的看法是這個問題背後的原因。代碼構建過程和嵌入式功能

以下三種方式來編寫的東西:

首先這裏的示例數據:

stackexample <- c(52,50,45,49.5,50.5,12,10,14,11.5,12,110,108,106,101,104) 
dim(stackexample)<- c(5,3) 

方法一:不要在該函數的數學沒有定義任何對象

ertimesIVCV1 <- function (x) 
{ (solve(var(log((x[-nrow(x),])/(x[-1,])))))%*% 
    ((1+(log(x[1,]/(x)[nrow(x),])))^(1/nrow(x))-1)} 

ertimesIVCV1(stackexample) 

方法二:在函數中定義對象,然後操縱這些對象

ertimesIVCV2 <- function (x) 
{ IVCV <- solve(var(log((x[-nrow(x),])/(x[-1,])))); 
    retsexcess <- (1+(log(x[1,]/(x)[nrow(x),])))^(1/nrow(x))-1; 
    IVCV%*%retsexcess} 

ertimesIVCV2(stackexample) 

方法三:定義幾個函數和調用這些函數在「總之喜歡」功能

IVCV <- function (x) {solve(var(log((x[-nrow(x),])/(x[-1,]))))} 
retsexcess <- function(x) (1+(log(x[1,]/(x)[nrow(x),])))^(1/nrow(x))-1 
ertimesIVCV3 <- function (x) {IVCV(x)%*%retsexcess(x)} 

ertimesIVCV3(stackexample) 

因此,所有產生相同的答案:

  [,1] 
[1,] 1.4430104 
[2,] -0.1365155 
[3,] 11.8088378 

,但你可以看到三種不同的方法。

作爲嵌入式函數的最佳數量是否存在這樣的事情?或者我們是否應該總是試圖明確列出所有數學?功能內多少層次的功能是最優的?在計算速度方面哪一種方法優越?這是否有一個經驗法則?你如何解決這個問題?任何意見或建議或鏈接將受到歡迎,並感謝你!

黑麥

+1

請參閱http://stackoverflow.com/q/4406873/210673,尤其是@ GavinSimpson的回答。 – Aaron 2012-02-28 19:41:33

回答

6

恕我直言,速度效率應該是最後你寫的代碼的關注,尤其是如果你是一個初學者。相反,您的主要關注點應該是簡單性,可讀性和模塊性。不要讀我錯,效率是一件好事,你會發現很多方法讓你的代碼在需要時更快,但它本身不應該是一個優先事項。

所以我會主要提供關於風格的提示。爲了說明,這裏是我的代碼版本的樣子。請記住,我不知道你的代碼是在計算什麼,所以我盡力用有意義的變量名分解它。

IVCV <- function(stack) { 

## This function computes [...] IVCV stands for [...] 
## Inputs: 
## - stack: a matrix where each column [...] 
## Output: a matrix [...] 

    n <- nrow(stack) # stack size 
    stack.ratios <- stack[-n, ]/stack[-1, ] 
    log.ratios <- log(stack.ratios) 
    ivcv   <- solve(var(log.ratios)) 

    return(ivcv) 
} 

ExcessReturn <- function(stack) { 

## This function computes [...] IVCV stands for [...] 
## Inputs: 
## - stack: a matrix where each column [...] 
## Output: a matrix [...] 

    n <- nrow(stack) # stack size 
    total.ratio <- stack[1, ]/stack[n, ] 
    excess.return <- (1 + log(total.ratio))^(1/n) - 1 

    return(excess.return) 
} 

ExcessReturnTimesIVCV <- function(stack) { 

## This function computes [...] IVCV stands for [...] 
## Inputs: 
## - stack: a matrix where each column [...] 
## Output: a vector [...] 

    return(IVCV(stack) %*% ExcessReturn(stack)) 
} 

1)是的,把你的代碼分解成小函數。可讀性,靈活性和維護性更好。它還使單元測試更容易,您可以在其中設計每個基本代碼段的測試。

2)通過在函數體內包含有關其描述/輸入/輸出的註釋來記錄函數。這樣,在創建函數後,用戶可以將其描述作爲函數打印輸出的一部分(例如,在GUI中輸入ExcessReturnTimesIVCV)。

3)將複雜性分解爲多個語句。現在,你的三個建議都很難理解,每一行都有太多事情要做。聲明應該做一件簡單的事情,以便輕鬆閱讀。創建更多的對象不會減慢你的過程,並且會使調試更容易。

4)您的對象名稱是使您的代碼清晰的關鍵。選擇它們並使用一致的語法。我使用UpperCamelCase作爲我自己的函數的名字,小寫字母用大多數其他對象的點分隔。

5)發表評論,特別是在3)和4)不足以使代碼清晰的情況下。在我的例子中,我選擇使用變量n。我反對推薦變量名稱應該是描述性的,但它是使代碼變得更輕一些,並給出了一些很好的對稱表達式stack[-n, ]/stack[-1, ]。由於n是一個不好的名字,我發表了一條解釋其含義的評論。如果我知道這些函數真的在做什麼,我也許會在代碼中加入更多的註釋。

6)使用一致的語法規則,主要是爲了提高可讀性。你會聽到關於這裏應該使用什麼的不同意見。一般來說,沒有最好的方法。最重要的是做出選擇並堅持下去。所以這裏有我的建議:

a)每行一個語句,沒有半分號。

b)一致的間距和縮進(無選項卡)。我在逗號後面放置空格,在二元運算符周圍。如果它有助於可讀性,我還會使用額外的間距排列。 c)一致的支撐:小心你用大括號來定義塊的方式,否則你很可能在腳本模式下出現問題。請參閱R Inferno的第8.1.43節(很好的參考)。

祝你好運!

6

如果目標是時間效率,然後用所提供的例子,答案是「誰在乎呢?」。函數調用的開銷並不決定效率。您應該專注於其他問題,例如用戶理解和維護代碼的能力。

require(rbenchmark) 
benchmark(replications=100, ver1= ertimesIVCV1(stackexample), 
ver2=ertimesIVCV2(stackexample), 
ver3 = ertimesIVCV3(stackexample)) 
# ------------------ 
    test replications elapsed relative user.self sys.self user.child sys.child 
1 ver1   100 0.030 1.000000  0.03  0   0   0 
2 ver2   100 0.030 1.000000  0.03  0   0   0 
3 ver3   100 0.031 1.033333  0.03  0   0   0 
4

不同意迪文(雖然不是真的,我只是把一個不同的旋轉)。如果目標是你的時間效率,那麼我們有一些情況。如果你做了一件事,那麼我同意「誰在乎?」。做任何你想要的東西/你當時想的任何東西,可能是方法1或2.

方法3的優點在於重複性。如果您輸入的代碼不止兩次,則效率會降低。把它放在一個功能上,並且省去了打字和忘記的可能性。我看到你已經在討論把某些東西放在一個函數中,但是你的IVCV函數可以作爲一個實用程序或其他函數派上用場嗎?如果不是,不要打擾它。

項目越大越好將它分解成各自具備的功能。這可以使組織,調試和修改更順利。