【问题标题】:Find the first non-zero column of a matrix (vectorized edition)查找矩阵的第一个非零列(向量化版)
【发布时间】:2014-05-30 20:45:46
【问题描述】:

我在问自己寻找矩阵的第一个非零列的值的最“矢量化”解决方案是什么样的。如果存在矢量化解决方案但非常丑陋/骇人听闻,我也要求最优雅的解决方案。

假设我们有一个矩阵M,我们可以假设它至少包含一个非零值:

 M =
     0     0     1     0     0
     0     0     2     0     0
     0     0     3     0     42
     0     0     4     0     0
     0     0     0     0     0

我想在第一列中找到不全为零的值;所以对于这个例子,期望的输出是:

 column = 
    1
    2
    3
    4
    0

我的第一次尝试使用了 for 循环并且工作正常,但它可能没有充分利用 matlab 中提供的工具。

>> for i = 1:size(M,2)
    col = M(:,i);
    if find(col) % empty array evaluates to false
        break;
    end
end
>> col
col =
     1
     2
     3
     4
     0

我想出的另一个解决方案是使用嵌套的 findcellfun 调用,但这可能仍然不是解决问题的最佳方法。

>> C = find(cellfun(@isempty, cellfun(@find, num2cell(M,1), 'UniformOutput', 0)) == 0)
C =
     3     5
>> M(:,C(1))
ans =
     1
     2
     3
     4
     0

【问题讨论】:

  • @Divakar 解决方案如此简单,真是令人尴尬。为什么不让您的评论成为答案?

标签: matlab find vectorization


【解决方案1】:

这是一种方法,我会把它留给你来衡量它的性能改进(如果你当然感兴趣的话)-

M(:,find(any(M),1))

我建议研究一下 Logical Operation in MATLABlogical indexing,因为它们对于索引目的非常方便。这些应该可以很好地为您服务。

【讨论】:

    【解决方案2】:

    正如您要求的“矢量化”解决方案,由于逻辑索引,这个解决方案应该运行得更快一些:

    tic; M(:,sum(M)>0); toc
    Elapsed time is 0.000020 seconds.
    
    tic; M(:,find(any(M),1)); toc
    Elapsed time is 0.000028 seconds.
    

    (虽然这不是衡量执行时间的最准确方法)

    编辑:

    更准确的方法是在更大的矩阵上使用timeit 进行测量:

    M=rand(1024); 
    f1= @() M(:,sum(M)>0);
    f2= @() M(:,find(any(M),1)); 
    t1=timeit(f1)
    t2=timeit(f2)
    
    t1 =
        0.0070
    t2 =
       2.3288e-05
    

    【讨论】:

    • sum 是不错的选择,但您需要find(..,1) 才能找到第一列。
    • @Divakar 如果总和为零,但列中并非所有元素都为零,该怎么办?
    • @timgeb 哦,是的!对于负数和正数的情况!需要额外的abs - M(:,sum(abs(M))>0)
    • 为了完整起见,它会是 M(:,find(sum(abs(M)) > 0,1))。
    猜你喜欢
    • 2015-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-13
    • 1970-01-01
    • 1970-01-01
    • 2016-03-02
    • 1970-01-01
    相关资源
    最近更新 更多