【问题标题】:MATLAB: duplicating vector 'n' times [duplicate]MATLAB:复制向量'n'次[重复]
【发布时间】:2012-05-06 03:57:41
【问题描述】:

我有一个向量,例如

vector = [1 2 3]

我想将它在其自身内复制 n 次,即如果 n = 3,它最终会是:

vector = [1 2 3 1 2 3 1 2 3]

对于任何 n 值,我怎样才能实现这一点?我知道我可以做到以下几点:

newvector = vector;
for i = 1 : n-1
    newvector = [newvector vector];
end

这似乎有点麻烦。还有更有效的方法吗?

【问题讨论】:

    标签: matlab vector


    【解决方案1】:

    试试

    repmat([1 2 3],1,3)
    

    我会让你检查repmat的文档。

    【讨论】:

      【解决方案2】:

      这是一种比 repmatreshape 快​​一个数量级的方法

      执行此类操作的最佳方法之一是使用Tony's Trick. Repmat 和 Reshape 通常比 Tony 的技巧慢,因为它直接使用 Matlabs 固有索引。为了回答你的问题,

      比方说,您想将行向量 r=[1 2 3] Nr=[1 2 3 1 2 3 1 2 3...] 一样平铺,然后,

      c=r'
      cc=c(:,ones(N,1));
      r_tiled = cc(:)';
      

      reshaperepmat 相比,对于大型N,此方法可显着节省时间。

      编辑:回复@Li-aung Yip 的疑问

      我进行了一个小的 Matlab 测试来检查 repmattony's trick 之间的速度差异。使用下面提到的代码,我计算了从基向量A=[1:N] 构造相同平铺向量的时间。结果表明,是的,Tony's-Trick 的速度快了一个数量级,尤其是对于较大的 N。欢迎大家自己尝试。如果必须在循环中执行这样的操作,那么这么大的时间差可能很关键。这是我使用的小脚本;

      N= 10 ;% ASLO Try for values N= 10, 100, 1000, 10000
      
      % time for tony_trick
      tic;
      A=(1:N)';
      B=A(:,ones(N,1));
      C=B(:)';
      t_tony=toc;
      clearvars -except t_tony N
      
      % time for repmat
      tic;
      A=(1:N);
      B=repmat(A,1,N);
      t_repmat=toc;
      clearvars -except t_tony t_repmat N
      

      两种方法的时间(以秒为单位)如下所示;

      • N=10,time_repmat = 8e-5,time_tony = 3e-5
      • N=100,time_repmat = 2.9e-4,time_tony = 6e-5
      • N=1000,time_repmat = 0.0302,time_tony = 0.0058
      • N=10000,time_repmat = 2.9199,time_tony = 0.5292

      我的 RAM 不允许我超过 N=10000。我敢肯定,对于 N=100000,这两种方法之间的时间差异会更加显着。我知道,对于不同的机器,这些时间可能会有所不同,但是时间数量级的相对差异会保持不变。此外,我知道,平均时间可能是一个更好的指标,但我只是想显示两种方法之间时间消耗的数量级差异。我的机器/操作系统详细信息如下:

      相关机器/操作系统/Matlab 详细信息:Athlon i686 Arch、Ubuntu 11.04 32 位、3gb ram、Matlab 2011b

      【讨论】:

      • 首先;什么?!其次,有人想知道为什么repmat() 比“手动”操作要慢。第三,任何使用它的人最好在它旁边发表评论......
      • research into Tony's Trick 之后,在撰写本文时它似乎更快 - 14 年前。从那时起,MATLAB 有了很大的改进,Tony's Trick 可能不再比repmat 快了。 (您应该编写一个基准测试并对此进行测试。;))
      • 会做的,谢谢你的链接。
      • 很好的答案:关于有证据支持的程序性能的声明。我在 SO 上看到很多关于程序性能的断言,很少有证据支持。我看不到自己经常使用 Tony's Trick,但后来我很少使用 repmat,现在我知道如果我发现 repmat 太慢了该去哪里找。
      • 好吧,我会被诅咒的。干得好。 :)
      【解决方案3】:

      根据 Abhinav 的回答和一些测试,我编写了一个总是比 repmat() 快的函数!

      它使用相同的参数,除了第一个参数必须是向量而不是矩阵。

      function vec = repvec( vec, rows, cols )
      %REPVEC Replicates a vector.
      %   Replicates a vector rows times in dim1 and cols times in dim2.
      %   Auto optimization included.
      %   Faster than repmat()!!!
      %   
      %   Copyright 2012 by Marcel Schnirring
      
          if ~isscalar(rows) || ~isscalar(cols)
              error('Rows and cols must be scaler')
          end
      
          if rows == 1 && cols == 1
              return  % no modification needed
          end
      
          % check parameters
          if size(vec,1) ~= 1 && size(vec,2) ~= 1
              error('First parameter must be a vector but is a matrix or array')
          end
      
          % check type of vector (row/column vector)
          if size(vec,1) == 1
              % set flag
              isrowvec = 1;
              % swap rows and cols
              tmp = rows;
              rows = cols;
              cols = tmp;
          else
              % set flag
              isrowvec = 0;
          end
      
          % optimize code -> choose version
          if rows == 1
              version = 2;
          else
              version = 1;
          end
      
          % run replication
          if version == 1
              if isrowvec
                  % transform vector
                  vec = vec';
              end
      
              % replicate rows
              if rows > 1
                  cc = vec(:,ones(1,rows));
                  vec = cc(:);
                  %indices = 1:length(vec);
                  %c = indices';
                  %cc = c(:,ones(rows,1));
                  %indices = cc(:);
                  %vec = vec(indices);
              end
      
              % replicate columns
              if cols > 1
                  %vec = vec(:,ones(1,cols));
                  indices = (1:length(vec))';
                  indices = indices(:,ones(1,cols));
                  vec = vec(indices);
              end
      
              if isrowvec
                  % transform vector back
                  vec = vec';
              end
          elseif version == 2
              % calculate indices
              indices = (1:length(vec))';
      
              % replicate rows
              if rows > 1
                  c = indices(:,ones(rows,1));
                  indices = c(:);
              end
      
              % replicate columns
              if cols > 1
                  indices = indices(:,ones(1,cols));
              end
      
              % transform index when row vector
              if isrowvec
                  indices = indices';
              end
      
              % get vector based on indices
              vec = vec(indices);
          end
      end
      

      随时使用您的所有数据测试该功能并给我反馈。当你发现一些可以改进的地方时,请告诉我。

      【讨论】:

      • 总是更快?我们可以看到一些数字,跨平台/操作系统/向量大小/等吗?
      猜你喜欢
      • 1970-01-01
      • 2013-04-22
      • 2019-11-12
      • 2016-01-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-09
      相关资源
      最近更新 更多