【发布时间】:2021-01-11 13:50:41
【问题描述】:
我有一系列方程系统,其中包含向量、矩阵和数组的总和和乘积,例如这个:
Y_i = \sum_{s=1}^S (1-alpha_{i,s})*R_i,
其中Y 和R 是长度为I 的向量,其元素分别为Y_i 和R_i,alpha 是具有I 行和S 列的矩阵。
现在我想在 R 中实现这些方程,但这样做要具有合理的“数学可读性”水平。特别是,我不是在寻找最短或最快执行的代码块,而是直观地反映原始数学表达式的代码块。对于上面的示例,我知道计算向量 Y 的一种快速简便的方法是向量化:
Y <- rowSums((1-alpha)*R)
但是,考虑到具有更多操作和更多维度的更复杂的表达式,我发现使用foreach 循环在所涉及的维度上基本上复制纸上的方程式更加直观,如下所示:
library(foreach)
Y <- foreach(i = 1:I, .combine = c) %:%
foreach(s = 1:S, .combine = sum) %do% {
(1-alpha[i,s])*R[i]
}
我真的很喜欢这里的结构和 .combine 参数,而且代码仍然有些简洁。不幸的是,这种方法的性能很糟糕,令人遗憾的是,它不可行。然后我尝试了sapply 循环:
Y <- sapply(1:I, function(i) {
sum(
sapply(1:S, function(s) {
(1-alpha[i,s])*R[i]
})
)
})
这种方法既快(不如矢量化方法快,但比foreach 方法快)和数学直观;但是,代码读起来很笨拙(只有二维七行)。因此我想问一下:你能想出一个更好的替代方法来解决这个问题(以及更复杂的变体)而不牺牲太多的计算速度、数学直觉或代码可读性吗?
【问题讨论】:
-
"preferable" 含糊不清,以至于过于基于意见。如果你可以向量化计算并且它比其他方法更快,为什么不坚持呢?直觉和可读性来自经验。 R 本身并不是最直观和易读的编程语言。如果您找到了一种惯用的(在 R 意义上)使其工作的方式,何必担心呢?
-
我不相信你的目标是合理的(甚至一般可以实现)。在任何情况下,都需要更加明确和具体地定义它。此外,您还需要考虑浮点精度。在某些应用程序中,这比您的所有其他问题更重要。
-
如果你想要代码可读性或数学直觉,最好直接将数学语言翻译成你的代码,例如嵌套
for循环。如果您更关心计算速度,则应该重新编写数学语言并对其进行优化作为第一步,这是以可读性为代价的。两个方面是取舍。取决于你真正追求什么。 -
您可以做的一件事是创建更具可读性的自定义函数。我一直这样做。然后你就有了可读的顶行代码,你可以深入研究。
-
感谢大家的意见。我主要担心的是可能有一个(我已经在做的功能/包/变体)我还不知道,但它完全符合我的要求。不幸的是,我想情况并非如此。我同意@JohnColeman 的观点,最终,只要有一些经验,就可以很容易地立即写下矢量化版本而无需考虑太多。现在,我将继续使用
sapply循环来测试我的代码,然后通过在我认为合适的地方引入矢量化来修改它。感谢您的讨论!