【问题标题】:Code Building Process and Embedded Functions代码构建过程和嵌入式功能
【发布时间】:2012-02-28 19:36:28
【问题描述】:

首先,这个问题不是关于尝试解决特定问题。作为 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)

方法三:定义几个函数并在“summary like”函数中调用这些函数

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

但是您可以看到三种不同的方法。

是否存在最佳数量的嵌入式函数,或者我们是否应该始终尝试明确列出所有数学运算?函数中有多少层函数是最优的?任何一种方法在计算速度上都更优越吗?这有经验法则吗?你如何处理这个问题?欢迎任何 cmets 或建议或链接,谢谢!

黑麦

【问题讨论】:

标签: r process


【解决方案1】:

恕我直言,速度效率应该是您在编写代码时最后考虑的问题,尤其是如果您是初学者。相反,您的主要关注点应该是简单性、可读性和模块化。不要误会我的意思,效率是一件好事,你会发现很多方法可以在需要时让你的代码更快,但它本身不应该是优先事项。

所以我将主要提供有关风格的提示。为了说明,这就是我的代码版本的样子。请记住,我不知道你的代码在计算什么,所以我尽我所能尝试使用有意义的变量名来破解它。

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) 通过在函数体中包含有关其描述/输入/输出的 cmets 来记录函数。这样,在创建函数后,用户可以在函数的打印输出中看到其描述(例如,只需在 GUI 中输入 ExcessReturnTimesIVCV)。

3) 将复杂性分解为多个语句。现在,你所有的三个建议都很难理解,每一行都发生了太多的事情。声明应该做一件简单的事情,以便于阅读。创建更多对象不太可能减慢您的进程,并且会使调试更加容易。

4) 您的对象名称是使您的代码清晰的关键。好好选择它们并使用一致的语法。我将 UpperCamelCase 用于我自己的函数名称,而使用点分隔的小写单词用于大多数其他对象。

5) 放置 cmets,尤其是在 3) 和 4) 不足以使代码清晰的地方。在我的示例中,我选择使用变量n。我反对变量名称应该是描述性的建议,但它是为了让代码更轻一些,并为stack[-n, ] / stack[-1, ] 之类的表达式提供一些很好的对称性。由于n 是一个坏名字,我在评论中解释了它的含义。如果我知道函数的真正作用,我可能还会在代码中添加更多 cmets。

6) 使用一致的语法规则,主要是为了提高可读性。你会听到关于这里应该使用什么的不同意见。一般来说,没有一种最好的方法。最重要的是做出选择并坚持下去。所以这是我的建议:

a) 每行一个语句,没有分号。

b) 一致的间距和缩进(无制表符)。我在逗号后加空格,围绕二元运算符。如果有助于可读性,我还会使用额外的间距来排列内容。

c) 一致的支撑:注意使用花括号定义块的方式,否则在脚本模式下可能会出现问题。请参阅R Inferno 的第 8.1.43 节(一个很好的参考。)

祝你好运!

【讨论】:

    【解决方案2】:

    如果目标是时间效率,那么所提供示例的答案是“谁在乎?”。函数调用的开销并不是决定效率的因素。您可能应该关注其他问题,例如用户理解和维护代码的能力。

     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
    

    【讨论】:

      【解决方案3】:

      不同意 DWin(虽然不是真的,我只是换个说法)。如果目标是您的时间效率,那么我们有一些案例。如果您只做一次,那么我同意“谁在乎?”。随心所欲/随心所欲,可能是方法 1 或 2。

      方法 3 的优势在于可重复性。如果您多次输入相同的代码,您的效率就会下降。把它放在一个函数中,避免打字和特别是错误打字的可能性。我看到您已经在谈论将东西放入函数中,但是您的 IVCV 函数会作为实用程序或其他函数派上用场吗?如果没有,请不要打扰它。

      项目越大,将其分解成具有自己功能的部分就越好。这可以使组织、调试和修改更加顺利。

      【讨论】:

        猜你喜欢
        • 2013-01-17
        • 2020-07-22
        • 1970-01-01
        • 1970-01-01
        • 2018-11-19
        • 1970-01-01
        • 2012-08-19
        • 1970-01-01
        • 2022-08-26
        相关资源
        最近更新 更多