代码构建过程和嵌入式功能

rsg*_*mon 5 r process

首先,这个问题不是试图解决具体问题.作为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)
Run Code Online (Sandbox Code Playgroud)

方法一:在函数中进行数学运算而不定义任何对象

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

ertimesIVCV1(stackexample)
Run Code Online (Sandbox Code Playgroud)

方法二:在函数中定义对象,然后操纵这些对象

    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)
Run Code Online (Sandbox Code Playgroud)

方法三:定义几个函数并在"类似摘要"函数中调用这些函数

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)
Run Code Online (Sandbox Code Playgroud)

所以都产生了相同的答案:

           [,1]
[1,]  1.4430104
[2,] -0.1365155
[3,] 11.8088378
Run Code Online (Sandbox Code Playgroud)

但正如你可以看到三种不同的方法.

是否存在嵌入式函数的最佳数量,还是应该总是尝试明确列出所有数学?函数中有多少级别的函数是最佳的?这两种方法的计算速度都优越吗?对此有经验吗?你怎么看待这个?欢迎任何意见或建议或链接,谢谢!

黑麦

42-*_*42- 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
Run Code Online (Sandbox Code Playgroud)


flo*_*del 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))
}
Run Code Online (Sandbox Code Playgroud)

1)是的,将代码分解为小函数.它的可读性,灵活性和维护性更好.它还使单元测试更容易,您可以在其中为每个基本代码设计测试.

2)通过在函数体内包含关于其描述/输入/输出的注释来记录函数.这样,在创建函数之后,用户可以将其描述视为函数打印输出的一部分(例如,只需键入ExcessReturnTimesIVCVGUI).

3)将复杂性分解为多个语句.现在,你的三条建议都难以理解,每条线上都有太多的东西.声明应该做一个简单的事情,以便它可以轻松阅读.创建更多对象不太可能减慢您的过程,并且它将使调试更容易.

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

5)发表评论,尤其是3)和4)不足以使代码清晰.在我的例子中,我选择使用变量n.我反对变量名称应该是描述性的建议,但它是为了使代码更轻stack[-n, ] / stack[-1, ]一些,并给出一些非常对称的表达式.由于n名字不好,我发表评论解释其含义.如果我知道函数真正在做什么,我可能还会在代码中添加更多注释.

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

a)每行一个陈述,没有半冒号.

b)一致的间距和压痕(无标签).我把逗号后面的空格放在二元运算符周围.如果它有助于提高可读性,我还会使用额外的间距排列.

c)一致的支撑:注意使用大括号来定义块的方式,否则你可能会在脚本模式下遇到问题.参见R Inferno的 8.1.43节(一个很好的参考).

祝好运!