R 中的外/张量积

发布于 2024-12-25 05:57:02 字数 830 浏览 5 评论 0 原文

给定每个维度 dp 向量 x1,x2,...,xp,计算其张量/外层/Kruskal 的最佳方法是什么产品(p-数组 X,其中条目 X[i1,i2,..ip] = x1[i1]x2[i2]...xp[ip]) ?循环是微不足道的,但很愚蠢。使用对 outer 的重复调用可以正常工作,但似乎不是最佳解决方案(显然,随着 p 的增加,速度会变慢)。有更好的办法吗?

编辑:

我目前最好的

array(apply(expand.grid(x1, x2, x3), 1, prod), dim=rep(d, 3))

至少是“感觉更好”...

编辑2:响应@Dwin,这是一个完整示例

d=3
x1 = 1:d
x2 = 1:d+3
x3 = 1:d+6
array(apply(expand.grid(x1, x2, x3), 1, prod), dim=rep(d, 3))

, , 1

     [,1] [,2] [,3]
[1,]   28   35   42
[2,]   56   70   84
[3,]   84  105  126

, , 2

     [,1] [,2] [,3]
[1,]   32   40   48
[2,]   64   80   96
[3,]   96  120  144

, , 3

     [,1] [,2] [,3]
[1,]   36   45   54
[2,]   72   90  108
[3,]  108  135  162

Given p vectors x1,x2,...,xp each of dimension d, what's the best way to compute their tensor/outer/Kruskal product (the p-array X with entries X[i1,i2,..ip] = x1[i1]x2[i2]...xp[ip])? Looping is trivial, but stupid. Using repeated calls to outer works OK, but doesn't seem like the optimal solution (and will get slower as p increases, obviously). Is there a better way?

Edit:

My current best is

array(apply(expand.grid(x1, x2, x3), 1, prod), dim=rep(d, 3))

which at least "feels better"...

Edit 2: In response to @Dwin, here's a complete example

d=3
x1 = 1:d
x2 = 1:d+3
x3 = 1:d+6
array(apply(expand.grid(x1, x2, x3), 1, prod), dim=rep(d, 3))

, , 1

     [,1] [,2] [,3]
[1,]   28   35   42
[2,]   56   70   84
[3,]   84  105  126

, , 2

     [,1] [,2] [,3]
[1,]   32   40   48
[2,]   64   80   96
[3,]   96  120  144

, , 3

     [,1] [,2] [,3]
[1,]   36   45   54
[2,]   72   90  108
[3,]  108  135  162

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

小嗷兮 2025-01-01 05:57:02

outer 的性能很难被超越。最终执行由 BLAS 库完成的矩阵乘法。重复调用 outer 也没关系,因为最后一次调用将主导速度和内存。例如,对于长度为 100 的向量,最后一次调用至少比前一个调用慢 100 倍...

在这里获得最佳性能的最佳选择是获得 R 的最佳 BLAS 库。默认的不是很好的。在 Linux 上,您可以相当轻松地配置 R 以使用 ATLAS BLAS。在 Windows 上,这更困难,但也是可能的。请参阅 R for Windows 常见问题解答

# multiple outer
mouter <- function(x1, ...) { 
    r <- x1
    for(vi in list(...)) r <- outer(r, vi)
    r
}

# Your example
d=3
x1 = 1:d
x2 = 1:d+3
x3 = 1:d+6 
mouter(x1,x2,x3)

# Performance test
x <- runif(1e2)
system.time(mouter(x,x,x))   # 0 secs (less than 10 ms)
system.time(mouter(x,x,x,x)) # 0.5 secs / 0.35 secs (better BLAS)

我将 Windows Rblas.dll 替换为 GOTO BLAS 的 DYNAMIC_ARCH 版本,网址为 这个地方 将时间从 0.5 秒缩短到 0.35 秒,如上所示。

It will be hard to beat the performance of outer. This ends up doing a matrix multiplication which is done by the BLAS library. Calling outer repeatedly doesn't matter either, since the last call will dominate both speed and memory wise. For example, for vectors of length 100, the last call is at least 100x slower than the previous one...

Your best bet to get the best performance here is to get the best BLAS library for R. The default one isn't very good. On Linux, you can fairly easily configure R to use ATLAS BLAS. On Windows it is harder, but possible. See R for Windows FAQ.

# multiple outer
mouter <- function(x1, ...) { 
    r <- x1
    for(vi in list(...)) r <- outer(r, vi)
    r
}

# Your example
d=3
x1 = 1:d
x2 = 1:d+3
x3 = 1:d+6 
mouter(x1,x2,x3)

# Performance test
x <- runif(1e2)
system.time(mouter(x,x,x))   # 0 secs (less than 10 ms)
system.time(mouter(x,x,x,x)) # 0.5 secs / 0.35 secs (better BLAS)

I replaced my Windows Rblas.dll with the DYNAMIC_ARCH version of GOTO BLAS at this place which improved the time from 0.5 to 0.35 secs as seen above.

蓝眸 2025-01-01 05:57:02

您可以使用 tensor 包。

还有 %o% 函数

A <- matrix(1:6, 2, 3)
D <- A %o% A

You can use tensor package.

And also %o% function

A <- matrix(1:6, 2, 3)
D <- A %o% A
寄风 2025-01-01 05:57:02

我发现自己想知道 kronecker 产品是否是您想要的。我无法从你的问题描述中确切地看出你想要什么,但是在一小部分参数上的元素是相同的(尽管与你批评的缓慢的 Chalasani 解决方案产生的排列不同:

kronecker( outer(LETTERS[1:2], c(3, 4, 5),FUN=paste), letters[6:8] ,FUN=paste)
     [,1]    [,2]    [,3]   
[1,] "A 3 f" "A 4 f" "A 5 f"
[2,] "A 3 g" "A 4 g" "A 5 g"
[3,] "A 3 h" "A 4 h" "A 5 h"
[4,] "B 3 f" "B 4 f" "B 5 f"
[5,] "B 3 g" "B 4 g" "B 5 g"
[6,] "B 3 h" "B 4 h" "B 5 h"

如果你想要产品,然后替换 prod 或“*” 在任何情况下,提供一组样本向量和所需的输出是提出问题的最佳实践。

I find myself wondering if the kronecker product is what you want. I cannot tell from your problem description exactly what is desired, but the elements from this on a small set of arguments are the same (albeit in a different arrangement as those in produced by Chalasani solution you were criticizing as slow:

kronecker( outer(LETTERS[1:2], c(3, 4, 5),FUN=paste), letters[6:8] ,FUN=paste)
     [,1]    [,2]    [,3]   
[1,] "A 3 f" "A 4 f" "A 5 f"
[2,] "A 3 g" "A 4 g" "A 5 g"
[3,] "A 3 h" "A 4 h" "A 5 h"
[4,] "B 3 f" "B 4 f" "B 5 f"
[5,] "B 3 g" "B 4 g" "B 5 g"
[6,] "B 3 h" "B 4 h" "B 5 h"

If you want products, then substitute either prod or "*". In any case offering a sample set of vectors and the desired output is a best practice in posing questions.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文