Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/matlab/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Matlab 根据给定位置选择矩阵条目_Matlab_Performance_Matrix_Optimization_Matrix Indexing - Fatal编程技术网

Matlab 根据给定位置选择矩阵条目

Matlab 根据给定位置选择矩阵条目,matlab,performance,matrix,optimization,matrix-indexing,Matlab,Performance,Matrix,Optimization,Matrix Indexing,我有以下矩阵(MxN,其中M≤ N) : 我想从每行中分别选择以下列条目(每行一个): 这意味着我们将元素保留在(1,3)、(2,1)和(3,4)中,数组的其余部分应为零 对于上面的示例,我将获得以下输出: 0 0 0.2785 0 0.9058 0 0 0 0 0 0 0.9706 我目前使用循环生成,当矩阵大小较大时,循环速度会变慢 有人能推荐一种

我有以下矩阵(MxN,其中M≤ N) :

我想从每行中分别选择以下列条目(每行一个):

这意味着我们将元素保留在(1,3)、(2,1)和(3,4)中,数组的其余部分应为零

对于上面的示例,我将获得以下输出:

     0         0    0.2785         0
0.9058         0         0         0
     0         0         0    0.9706
我目前使用循环生成,当矩阵大小较大时,循环速度会变慢


有人能推荐一种更高效的方法吗?

您可以使用
sub2ind
函数将条目索引转换为线性索引

使用线性索引时,matlab将矩阵视为长列向量

org_mat=[0.8147    0.9134    0.2785    0.9649
0.9058    0.6324    0.5469    0.1576
0.1270    0.0975    0.9575    0.9706];
entries=[3,1,4];

linear_entries=sub2ind(size(org_mat),1:length(entries),entries);
new_mat=zeros(size(org_mat));
new_mat(linear_entries)=org_mat(linear_entries);

这应该比sub2ind快:

m = [0.8147, 0.9134, 0.2785, 0.9649;
0.9058, 0.6324, 0.5469, 0.1576;
0.1270, 0.0975, 0.9575,   0.9706];

n=[3,1,4];

linear = (1:length(n)) + (n-1)*size(m,1);
new_m = zeros(size(m));
new_m(linear) = m(linear);

关于绩效的其他回答/评论中有一些讨论。这是一种情况,一个简单(构造良好的)
for
循环将很好地完成工作,基本上不会对性能产生影响

% For some original matrix 'm', and column indexing array 'idx':
x = zeros( size(m) ); % Initialise output of zeros
for ii = 1:numel(idx) % Loop over indices
    % Assign the value at the column index for this row
    x( ii, idx(ii) ) = m( ii, idx(ii) );     
end
这段代码可读性强,速度快。为了证明“快速”的合理性,我已经为所有4种当前答案的方法编写了以下基准测试代码,运行在MatlabR2017B上。以下是输出图

  • 对于“小”矩阵,最多2^5列和2^4行:

  • 对于“大”矩阵,最多2^15列和2^14行(使用和不使用
    bsxfun
    解决方案的绘图相同,因为这会破坏缩放):

第一个情节可能有点误导。虽然结果是一致的(即性能排名慢-快是
bsxfun
然后
sub2ind
然后手动索引然后循环),但y轴是10^(-5)秒,因此使用哪种方法基本上无关紧要

第二个图显示,对于大型矩阵,这些方法基本上是等效的,除了
bsxfun
,这很糟糕(这里没有显示,但它需要更多内存)

我会选择更清晰的循环,它允许您更灵活,并且您会确切地记得两年后它在代码中所做的事情


基准代码:

function benchie() 
    K = 5;                      % Max loop variable
    T = zeros( K, 4 );          % Timing results
    for k = 1:K
        M = 2^(k-1); N = 2^k;   % size of matrix
        m = rand( M, N );       % random matrix
        idx = randperm( N, M ); % column indices

        % Define anonymous functions with no inputs for timeit, and run
        f1 = @() f_sub2ind( m, idx ); T(k,1) = timeit(f1);
        f2 = @() f_linear( m, idx );  T(k,2) = timeit(f2);
        f3 = @() f_loop( m, idx );    T(k,3) = timeit(f3);   
        f4 = @() f_bsxfun( m, idx );  T(k,4) = timeit(f4);   
    end
    % Plot results
    plot( (1:K)', T, 'linewidth', 2 );
    legend( {'sub2ind', 'linear', 'loop', 'bsxfun'} );
    xlabel( 'k, where matrix had 2^{(k-1)} rows and 2^k columns' );
    ylabel( 'function time (s)' )
end

function f_sub2ind( m, idx )
    % Using the in-built sub2ind to generate linear indices, then indexing
    lin_idx = sub2ind( size(m), 1:numel(idx), idx );
    x = zeros( size(m) );
    x( lin_idx ) = m( lin_idx );
end
function f_linear( m, idx )
    % Manually calculating linear indices, then indexing
    lin_idx = (1:numel(idx)) + (idx-1)*size(m,1);
    x = zeros( size(m) );
    x( lin_idx ) = m( lin_idx );
end
function f_loop( m, idx )
    % Directly indexing in a simple loop
    x = zeros( size(m) );
    for ii = 1:numel(idx)
        x( ii, idx(ii) ) = m( ii, idx(ii) );
    end
end
function f_bsxfun( m, idx )
    % Using bsxfun to create a logical matrix of desired elements, then masking
    % Since R2016b, can use 'x = ( (1:size(m,2)) == idx(:) ) .* m;'
    x = bsxfun(@eq, 1:size(m,2), idx(:)).*m;
end
bsxfun
无参与方

m
为输入矩阵,
idx
为带列索引的向量。您可以从
idx
构建逻辑掩码,并用
m
乘以元素,如下所示:

result = bsxfun(@eq, 1:size(m,2), idx(:)).*m;

TL;DR-这是我的建议:

nI = numel(idx);
sz = size(m); 
x = sparse( 1:nI, idx, m(sub2ind( size(m), 1:numel(idx), idx )), sz(1), sz(2), nI);
文章的其余部分讨论了为什么它工作得更好


看到期望的输出矩阵主要由零组成,这实际上需要使用!这不仅可以提高性能(尤其是对于较大的矩阵),还应该对内存更加友好

我将向其中添加两个函数:

本质上的区别在于,我们不是将输出预分配为一个零数组,而是作为一个稀疏数组。基准1的结果如下:

result = bsxfun(@eq, 1:size(m,2), idx(:)).*m;

。。。这就提出了一个问题-为什么
稀疏
方法要快一个数量级

为了回答这个问题,我们应该查看基准测试函数中的实际运行时分布,我们可以从中获得。要获得更多信息,我们可以使用
profile('-memory',on')
。在运行基准测试的较短版本2(仅针对最高值
k
运行)后,我们得到:

因此,我们可以得出以下几点结论:

  • 运行时的绝大多数时间都花在分配和释放内存上,这就是为什么这些算法似乎具有几乎相同的性能。因此,如果我们减少内存分配,我们可以直接节省时间(对于
    sparse
    !)来说是一个大加号
  • 即使
    sub2ind
    loop
    方法看起来是一样的,我们仍然可以在这两种方法中建立一个“赢家”(参见下图中的紫色框)sub2ind!
    sub2ind
    32毫秒,而循环为41毫秒
  • 正如
    mlint
    警告我们的那样,稀疏循环方法的速度并不令人惊讶:

    解释

    代码分析器检测可能较慢的稀疏数组的索引模式。更改稀疏数组的非零模式的赋值可能会导致此错误,因为此类赋值会导致相当大的开销

    建议的行动

    如果可能,使用以下方法构建稀疏数组,并且不要使用索引分配(例如C(4)=B)来构建稀疏数组:

  • 创建单独的索引和值数组
  • 调用sparse来组装索引和值数组
  • 如果必须使用索引指定来构建稀疏数组,则可以通过首先使用预分配稀疏数组来优化性能

    如果代码只更改已经非零的数组元素,那么开销是合理的。抑制此消息,如中所述

    有关详细信息,请参阅“”

  • 该方法结合了两个方面的优点,即
    sparse
    的内存节省和
    sub2ind
    的矢量化,似乎是运行时间仅为3ms的最佳方法
    1制作图表的代码:

    function q51605093()
        K = 15;                     % Max loop variable
        T = zeros( K, 4 );          % Timing results
        for k = 1:K
            M = 2^(k-1); N = 2^k;   % size of matrix
            m = rand( M, N );       % random matrix
            idx = randperm( N, M ); % column indices
    
            % Define anonymous functions with no inputs, for timeit, and run
            f = cell(4,1);
            f{1} = @() f_sub2ind( m, idx ); 
            f{2} = @() f_loop( m, idx );   
            f{3} = @() f_sp_loop( m, idx );
            f{4} = @() f_sp_sub2ind( m, idx );
            T(k,:) = cellfun(@timeit, f);
    
            if k == 5 % test equality during one of the runs
              R = cellfun(@feval, f, 'UniformOutput', false);
              assert(isequal(R{:}));
            end
        end
        % Plot results
        figure();
        semilogy( (1:K).', T, 'linewidth', 2 ); grid on; xticks(0:K);
        legend( {'sub2ind', 'loop', 'sp\_loop', 'sp\_sub2ind'}, 'Location', 'NorthWest' );
        xlabel( 'k, where matrix had 2^{(k-1)} rows and 2^k columns' );
        ylabel( 'function time (s)' )    
    end
    
    function x = f_sub2ind( m, idx )
        % Using the in-built sub2ind to generate linear indices, then indexing
        lin_idx = sub2ind( size(m), 1:numel(idx), idx );
        x = zeros( size(m) );
        x( lin_idx ) = m( lin_idx );
    end
    
    function x = f_loop( m, idx )
        % Directly indexing in a simple loop
        x = zeros( size(m) );
        for ii = 1:numel(idx)
            x( ii, idx(ii) ) = m( ii, idx(ii) );
        end
    end
    
    function x = f_sp_loop( m, idx )
      nI = numel(idx);
      sz = size(m); 
      x = spalloc( sz(1), sz(2), nI ); % Initialize a sparse array.
      for indI = 1:nI
          x( indI, idx(indI) ) = m( indI, idx(indI) ); % This generates a warning (inefficient)
      end
    end
    
    function x = f_sp_sub2ind( m, idx )
      nI = numel(idx);
      sz = size(m); 
      x = sparse( 1:nI, idx, m(sub2ind( size(m), 1:numel(idx), idx )), sz(1), sz(2), nI);
    end
    
    2用于分析的代码:

    function q51605093_MB()
        K = 15;                 % Max loop variable
        M = 2^(K-1); N = 2^K;   % size of matrix
        m = rand( M, N );       % random matrix
        idx = randperm( N, M ); % column indices
    
        % Define anonymous functions with no inputs, for timeit, and run
        f = cell(4,1);
        f{1} = f_sub2ind( m, idx ); 
        f{2} = f_loop( m, idx );   
        f{3} = f_sp_loop( m, idx );
        f{4} = f_sp_sub2ind( m, idx );
    
    %     assert(isequal(f{:}));
    end
    
    ... the rest is the same as above
    

    这意味着(特别是R2016b之后)这是迄今为止最优雅的解决方案,
    result=((1:size(m,2))==idx(:).*m
    @Wolfies和最慢的:-p刚刚添加到我的中,它对于小矩阵来说非常具有可比性,所以我倾向于整洁,但是对于大矩阵来说它非常差!我真的很欣赏这个简单的解决方案,谢谢@Luis,我也指出这是一个有用的答案。考虑到稀疏矩阵不像普通矩阵那样“友好”,为了完整性,可能值得在最后加入一个
    full
    调用。这将添加回内存分配中,但在稀疏分配之后使用它可能更有效
    function q51605093()
        K = 15;                     % Max loop variable
        T = zeros( K, 4 );          % Timing results
        for k = 1:K
            M = 2^(k-1); N = 2^k;   % size of matrix
            m = rand( M, N );       % random matrix
            idx = randperm( N, M ); % column indices
    
            % Define anonymous functions with no inputs, for timeit, and run
            f = cell(4,1);
            f{1} = @() f_sub2ind( m, idx ); 
            f{2} = @() f_loop( m, idx );   
            f{3} = @() f_sp_loop( m, idx );
            f{4} = @() f_sp_sub2ind( m, idx );
            T(k,:) = cellfun(@timeit, f);
    
            if k == 5 % test equality during one of the runs
              R = cellfun(@feval, f, 'UniformOutput', false);
              assert(isequal(R{:}));
            end
        end
        % Plot results
        figure();
        semilogy( (1:K).', T, 'linewidth', 2 ); grid on; xticks(0:K);
        legend( {'sub2ind', 'loop', 'sp\_loop', 'sp\_sub2ind'}, 'Location', 'NorthWest' );
        xlabel( 'k, where matrix had 2^{(k-1)} rows and 2^k columns' );
        ylabel( 'function time (s)' )    
    end
    
    function x = f_sub2ind( m, idx )
        % Using the in-built sub2ind to generate linear indices, then indexing
        lin_idx = sub2ind( size(m), 1:numel(idx), idx );
        x = zeros( size(m) );
        x( lin_idx ) = m( lin_idx );
    end
    
    function x = f_loop( m, idx )
        % Directly indexing in a simple loop
        x = zeros( size(m) );
        for ii = 1:numel(idx)
            x( ii, idx(ii) ) = m( ii, idx(ii) );
        end
    end
    
    function x = f_sp_loop( m, idx )
      nI = numel(idx);
      sz = size(m); 
      x = spalloc( sz(1), sz(2), nI ); % Initialize a sparse array.
      for indI = 1:nI
          x( indI, idx(indI) ) = m( indI, idx(indI) ); % This generates a warning (inefficient)
      end
    end
    
    function x = f_sp_sub2ind( m, idx )
      nI = numel(idx);
      sz = size(m); 
      x = sparse( 1:nI, idx, m(sub2ind( size(m), 1:numel(idx), idx )), sz(1), sz(2), nI);
    end
    
    function q51605093_MB()
        K = 15;                 % Max loop variable
        M = 2^(K-1); N = 2^K;   % size of matrix
        m = rand( M, N );       % random matrix
        idx = randperm( N, M ); % column indices
    
        % Define anonymous functions with no inputs, for timeit, and run
        f = cell(4,1);
        f{1} = f_sub2ind( m, idx ); 
        f{2} = f_loop( m, idx );   
        f{3} = f_sp_loop( m, idx );
        f{4} = f_sp_sub2ind( m, idx );
    
    %     assert(isequal(f{:}));
    end
    
    ... the rest is the same as above