循环内哪个函数更高效(ncol/nrow() 还是 dim())?

3

我正在尝试使用for循环创建一个乘法表。我是编程新手,R是我学习的第一种语言,因此我想知道循环内部的哪些函数更快、更有效。目前,我没有使用apply家族的方法,因为我认为理解基本函数如循环非常重要。

以下是我用来创建乘法表的两种方法:

使用dim()函数:

mtx <- matrix(nrow=10, ncol=10)

for(i in 1:dim(mtx)[1]){
  for(j in 1:dim(mtx)[2]){
    mtx[i,j] <- i*j
  }
}

使用ncol/nrow()函数:

mtx <- matrix(nrow=10, ncol=10)

for(i in 1:ncol(mtx)){
  for(j in 1:nrow(mtx)){
    mtx[i,j] <- i*j
  }
}

哪种方式更高效、更普遍适用呢?
谢谢。

2
你试过计时吗?另外,你看过ncol的代码吗? - A5C1D2H2I1M1N2O1R2T1
你好 A5C1D2H2I1M1N2O1R2T1 ,感谢您的迅速回复。我尝试在控制台中输入不带括号的ncol并发现它使用了“dim(x)[2L]”。这是否意味着这两个函数在速度上是相同的? - Schleifer Grigorij
我尝试对具有10000列/行的矩阵执行两个函数的时间。使用 ´ncol()´ 方法运行需要很长时间,或者我的计算机出了问题。 - Schleifer Grigorij
1
如果你对效率感兴趣,那么你关注的代码部分可能是错误的。你应该学会对代码进行性能分析。当然,你也不应该使用循环来实现这个。 - Roland
我会使用(1:rows) %*% t(1:cols) - Roland
或者更好的是 tcrossprod(1:rows, 1:cols) - Roland
1个回答

4

如果您像示例中那样使用函数,它们的差异实际上微不足道。这是因为函数只在每个循环定义中调用一次(而不是每个循环迭代!)

我肯定更喜欢使用ncol/nrow,因为它比dim(x)[1]更容易阅读。

话虽如此,如果您只关注时间,dim函数比ncol/nrow更快。如果您查看源代码,可以看到ncol的实现方式为

function (x) 
dim(x)[2L]

这意味着ncol调用了dim,因此速度稍慢。
如果你想在处理大矩阵时真正节省一些速度,我建议先像这样创建循环向量:
rows <- 1:nrow(mtx)
cols <- 1:ncols(mtx)
for (i in rows) {
    for (j in cols) {
        mtx[i, j] <- i * j    
    }
}

1
这很可能与原始速度几乎相同。要真正加速,请尝试 outer(1:rows, 1:cols,“*”) - Hong Ooi
对于小矩阵,它们确实非常相似。但是,如果您有许多列的矩阵,则原始版本将为每一行再次分配向量“1:ncol(mtx)”的内存,这可能会很慢!无论如何,您的版本肯定更快,但OP说他想学习for循环。 - AEF
是的,微基准测试显示,当使用一个有50行和1000000列的矩阵时,速度提升了约50%。 - AEF
@AEF 现在和这个进行比较(https://dev59.com/pKDha4cB1Zd3GeqP_Cjx#42904111?noredirect=1#comment72907866_42903707)。如果 OP 抱怨 R 冻结,50% 的加速也无济于事。 - Roland
@Roland,是的,我完全意识到有更快的解决方案,我同意你的解决方案在任何实际情况下都更好。然而,OP特别提到他想学习和理解for循环。 - AEF
是的,但他们的工作基于错误的前提:在R中,理解for循环不如理解向量化、矩阵代数等重要。而试图优化此任务的for循环效率只是浪费精力。 - Roland

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接