首先,这个问题不是试图解决具体问题。作为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
但是你可以看到三种不同的方法。
是否存在嵌入式函数的最佳数量,还是应该总是尝试明确列出所有数学?函数中有多少级别的函数是最佳的?这两种方法的计算速度都优越吗?对此有经验吗?你怎么看待这个?欢迎任何意见或建议或链接,谢谢!
黑麦
答案 0 :(得分: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
答案 1 :(得分: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节(一个很好的参考资料。)
祝你好运!答案 2 :(得分:4)
不同意DWin(虽然不是真的,我只是对它进行了不同的旋转)。如果目标是你的时间效率,那么我们就有了一些案例。如果你做了一次,那么我同意“谁在乎?”。做你想做的事情/你当时的想法,可能是方法1或2。
方法3的优点在于可重复性。如果您输入相同的代码超过两次,则效率会下降。把它放在一个函数中,并保存自己的输入和特别错误输入的可能性。我看到你已经在谈论将东西放在一个函数中,但是你的IVCV
函数会作为实用程序或其他函数派上用场吗?如果没有,请不要理会它。
项目越大,将其分解为获得自己功能的部分就越好。这可以使组织,调试和修改更加顺利。