【问题标题】:Is there a fast way to expand matrices n times by duplicating each line?有没有一种通过复制每一行来快速扩展矩阵 n 次的方法?
【发布时间】:2016-07-14 18:50:02
【问题描述】:

例如,[1 1 ; 2 2 ; 3 3] 变为

[1 1
 1 1
 1 1
 2 2
 2 2
 2 2
 3 3
 3 3
 3 3]

我正在使用这个: Julia 中的 expander(orig,mult::Int) = orig[ceil(Int,(1:size(orig,1)*mult)/mult),:]; 和 Matlab 中的以下内容:

function expanded = expander(original,multiplier)
   expanded = original(ceil((1:size(original,1)*multiplier)/multiplier),:);
end

另一个 matlab 唯一的方法是:

expanded = kron(original,ones(multiplier,1));

如果存在,我更喜欢超快的 julia 选项。

【问题讨论】:

  • kron 是最好的方法,在这个问题得到修复后,Julia 的速度非常快:github.com/JuliaLang/julia/issues/4958
  • 是什么阻止您在 Julia 中以同样的方式使用 kron
  • 如果 kron 是最快的方法,那我会用。它是否更快,因为它避免了从 int 更改为 double 然后返回?
  • 因为你也用[matlab] 标记了这个问题:你可以使用repmat。但是不知道相比之下它有多快。
  • 对于 Matlab R2015a+ 尝试 repelem,例如,A=[1 1;2 2;3 3]; repelem(A,3,1)

标签: arrays matlab multidimensional-array julia


【解决方案1】:

这并不能证明kron 是最快的,但我将它的时间与填充类似大小的数组所需的时间进行了比较,kron 做得很好:

original = [1 1 ; 2 2 ; 3 3];
multiplier = 3*10^6;

@time begin
    for idx = 1:100
        expanded = kron(original,ones(multiplier));
    end
end
## 9.199143 seconds (600 allocations: 15.646 GB, 9.05% gc time)

@time begin
    for idx = 1:100
        myones = [ones(multiplier*size(original,1))  ones(multiplier*size(original,1))];
    end
end
## 12.746123 seconds (800 allocations: 26.822 GB, 14.86% gc time)

更新 作为对 David Sanders 的 cmets 的回应,以下是封装在函数中的测试。我在全局范围内进行测试的原因(我知道这不是正常的最佳实践)是因为在我看来,对象可能会在全局范围内创建,这似乎很合理。

function kron_test(original, multiplier)
    for idx = 1:100
        expanded = kron(original,ones(multiplier));
    end
end

function ones_test(original, multiplier)
    for idx = 1:100
        myones = [ones(multiplier*size(original,1))  ones(multiplier*size(original,1))];
    end
end

## times given after first function call to compile
@time kron_test(original, multiplier);  ## 11.107632 seconds (604 allocations: 15.646 GB, 23.98% gc time)
@time ones_test(original, multiplier);  ## 15.849761 seconds (604 allocations: 26.822 GB, 33.50% gc time)

【讨论】:

  • 记住永远不要在全局范围内计时anything,这意味着什么。
  • @DavidP.Sanders 总体来说很好。但是,如果您要在全局范围内创建变量,那么全局时间是否合适?不过,我很高兴知道这是否不正确。
  • 如果你传入变量,你会在本地范围内得到一个不同的同名变量。您可以使用本地和全局关键字在它们之间切换。
【解决方案2】:

就个人而言,我只会使用repeat

repeat(original, inner=(multiplier, 1))

kron 不同,它非常易读易懂。不幸的是,它有点慢。即便如此,如果您已将 kron 确定为性能瓶颈,我只会使用它。虽然计算机的执行速度更快,但人类理解正在发生的事情要慢得多……repeat 的性能最终应该会变得更好(它是issue #15553)。


编辑:从 Julia 1.2 开始,repeat 确实变得更快了。它现在可以与 kron 竞争:

julia> @btime kron($original,ones($multiplier));
  81.039 ms (6 allocations: 160.22 MiB)

julia> @btime repeat($original, inner=($multiplier, 1));
  84.087 ms (27 allocations: 137.33 MiB)

【讨论】:

    【解决方案3】:

    你可以的

    a = [1 1 ; 2 2 ; 3 3]
    a = a' #matrices are in column major order in julia, should  be faster this way
    a = repmat(a,1,n) 
    a = sortcols(a)
    

    不幸的是,我不知道这种方法是否“超快”,但它相对简单直观

    【讨论】:

      猜你喜欢
      • 2011-09-24
      • 1970-01-01
      • 2014-07-19
      • 1970-01-01
      • 2022-12-12
      • 2021-01-08
      • 1970-01-01
      • 2012-08-31
      • 2021-04-17
      相关资源
      最近更新 更多