Matlab:创建矩阵,其行是相同的向量。使用repmat()或乘以()

时间:2015-09-26 13:20:02

标签: arrays matlab matrix

我想通过将矢量连接到自身n次来从矢量创建矩阵。因此,如果我的向量是mx1,那么我的矩阵将是mxn,并且矩阵的每列将等于向量。

以下哪项是最好/最正确的方式,或者有更好的方式我不知道?

matrix = repmat(vector, 1, n);
matrix = vector * ones(1, n);

由于

4 个答案:

答案 0 :(得分:4)

以下是使用timeit 不同矢量大小重复因子基准测试。要显示的结果是Windows上的Matlab R2015b。

首先为每个考虑的方法定义一个函数:

%// repmat approach
function matrix = f_repmat(vector, n)
matrix = repmat(vector, 1, n);

%// multiply approach
function matrix = f_multiply(vector, n)
matrix = vector * ones(1, n);

%// indexing approach
function matrix = f_indexing(vector,n)
matrix = vector(:,ones(1,n));

然后生成不同大小的向量,并使用不同的重复因子:

M = round(logspace(2,4,15)); %// vector sizes
N = round(logspace(2,3,15)); %// repetition factors
time_repmat   = NaN(numel(M), numel(N)); %// preallocate results
time_multiply = NaN(numel(M), numel(N));
time_indexing = NaN(numel(M), numel(N));
for ind_m = 1:numel(M);
    for ind_n = 1:numel(N);
        vector = (1:M(ind_m)).';
        n = N(ind_n);
        time_repmat(ind_m, ind_n)   = timeit(@() f_repmat(vector, n)); %// measure time
        time_multiply(ind_m, ind_n) = timeit(@() f_multiply(vector, n));
        time_indexing(ind_m, ind_n) = timeit(@() f_indexing(vector, n));
    end
end

结果绘制在以下两个图中,使用repmat作为参考

figure
imagesc(time_multiply./time_repmat)
set(gca, 'xtick',1:2:numel(N), 'xticklabels',N(1:2:end))
set(gca, 'ytick',1:2:numel(M), 'yticklabels',M(1:2:end))
title('Time of multiply / time of repmat')
axis image
colorbar

figure
imagesc(time_indexing./time_repmat)
set(gca, 'xtick',1:2:numel(N), 'xticklabels',N(1:2:end))
set(gca, 'ytick',1:2:numel(M), 'yticklabels',M(1:2:end))
title('Time of indexing / time of repmat')
axis image
colorbar

enter image description here enter image description here

或许更好的比较表明,对于每个测试的矢量大小和重复因子,三种方法中哪一种最快

figure
times = cat(3, time_repmat, time_multiply, time_indexing);
[~, fastest] = min(times, [], 3);
imagesc(fastest)
set(gca, 'xtick',1:2:numel(N), 'xticklabels',N(1:2:end))
set(gca, 'ytick',1:2:numel(M), 'yticklabels',M(1:2:end))
title('1: repmat is fastest; 2: multiply is; 3: indexing is')    
axis image
colorbar

enter image description here

可以从数字中得出一些结论

  • 基于乘法的方法总是慢于repmat
  • 基于索引的方法类似于repmat。对于较大的矢量大小或重复因子值,它往往更快,而对于较小的值则较慢。

答案 1 :(得分:2)

如果它们为您提供所需的输出,则这两种方法都是正确的。

但是,根据您声明向量的方式,如果您使用repmat,则ones可能会发现错误的结果。例如,举个例子

>> v = 1:10;
>> m = v * ones(1, n)
Error using  * 
Inner matrix dimensions must agree.
>> m = repmat(v, 1, n)
m =

  Columns 1 through 22

     1     2     3     4     5     6     7     8     9    10     1     2     3     4     5     6     7     8     9    10     1     2

  Columns 23 through 44

     3     4     5     6     7     8     9    10     1     2     3     4     5     6     7     8     9    10     1     2     3     4

  Columns 45 through 50

     5     6     7     8     9    10

ones提供错误,告知您没有做正确的事,但repmat却没有。虽然此示例适用于repmatones

>> v = (1:10).';
>> m = v * ones(1, n)
m =

     1     1     1     1     1
     2     2     2     2     2
     3     3     3     3     3
     4     4     4     4     4
     5     5     5     5     5
     6     6     6     6     6
     7     7     7     7     7
     8     8     8     8     8
     9     9     9     9     9
    10    10    10    10    10
>> m = repmat(v, 1, n)
m =

     1     1     1     1     1
     2     2     2     2     2
     3     3     3     3     3
     4     4     4     4     4
     5     5     5     5     5
     6     6     6     6     6
     7     7     7     7     7
     8     8     8     8     8
     9     9     9     9     9
    10    10    10    10    10

答案 2 :(得分:2)

两者都是正确的,但repmat是多维矩阵复制的更通用的解决方案,因此必然比其他解决方案慢。将两个向量相乘的特定“自制”解决方案可能更快。选择而不是乘法可能更快,即vector(:,ones(n,1))而不是vector*ones(1,n)

编辑: 在命令窗口中键入open repmat。如您所见,它不是内置函数。您可以看到它还使用ones(选择)来复制矩阵。但是,由于它是一种更通用的解决方案(对于标量和多维矩阵以及多个方向的副本),您将发现不必要的if语句和其他不必要的代码,从而有效地降低了速度。

编辑: 对于非常大的向量,使用ones的乘法向量变得更慢。明确的获胜者使用ones进行选择,即vector(:,ones(n,1))(由于它使用相同的策略,因此应始终比repmat更快。)

答案 3 :(得分:2)

您也可以这样做 -

vector(:,ones(1,n))

但是,如果我必须选择,repmat将成为我的首选方法,因为它完全是出于此目的。此外,根据您将如何使用此复制数组,您可以完全避免使用bsxfun创建它,该Comparing BSXFUN and REPMAT在其输入数组上进行动态复制,并在输入上应用某些操作。这是一个比较 - @covers annotation在大多数情况下bsxfun显示优于repmat

基准

为了表现,让我们测试一下这些。这是一个基准代码 -

%// Inputs
vector = rand(1000,1);
n = 1000;

%// Warm up tic/toc.
for iter = 1:50000
    tic(); elapsed = toc();
end

disp(' ------- With REPMAT -------')
tic,
for iter = 1:200
    A = repmat(vector, 1, n);
end
toc, clear A

disp(' ------- With vector(:,ones(1,n)) -------')
tic,
for iter = 1:200
    A = vector(:,ones(1,n));
end
toc, clear A

disp(' ------- With vector * ones(1, n) -------')
tic,
for iter = 1:200
    A = vector * ones(1, n);
end
toc

运行时结果 -

 ------- With REPMAT -------
Elapsed time is 1.241546 seconds.
 ------- With vector(:,ones(1,n)) -------
Elapsed time is 1.212566 seconds.
 ------- With vector * ones(1, n) -------
Elapsed time is 3.023552 seconds.