【问题标题】:Matlab Convert Vector to Binary Matrix [duplicate]Matlab将向量转换为二进制矩阵[重复]
【发布时间】:2015-09-09 17:55:30
【问题描述】:

我有一个大小为 (m,1) 的向量 v,其元素是从 1:n 中挑选的整数。我想创建一个大小为 (m,n) 的矩阵 M,如果 v(i) = j,其元素 M(i,j) 为 1,否则为 0。我不想使用循环,只想将其实现为简单的向量矩阵操作。

所以我首先想到的是,创建一个包含重复元素的矩阵

 M = v * ones(1,n) % this is a (m,n) matrix of repeated v

例如 v=[1,1,3,2]' m = 4 和 n = 3

M =
     1     1     1
     1     1     1
     3     3     3
     2     2     2

那么我需要创建一个大小为 (1,n) 的比较向量 c

c = 1:n
1 2 3

那我需要进行一系列的逻辑比较

M(1,:)==c % this results in [1,0,0]
.
M(4,:)==c % this results in [0,1,0]

但是,我认为应该可以执行通过紧凑矩阵表示法遍历每一行的最后步骤,但我很难过,并且对索引不够了解。 最终结果应该是

M =
     1     0     0
     1     0     0
     0     0     1
     0     1     0

【问题讨论】:

    标签: arrays matlab matrix vector matrix-indexing


    【解决方案1】:

    bsxfun 的一个非常简单的调用就可以解决问题:

    >> n = 3;
    >> v = [1,1,3,2].';
    >> M = bsxfun(@eq, v, 1:n)
    
    M =
    
         1     0     0
         1     0     0
         0     0     1
         0     1     0
    

    代码的工作原理实际上非常简单。 bsxfun 是所谓的 Binary Singleton EXpansion 函数。这样做是您提供两个任意大小的数组/矩阵,只要它们是可广播的。这意味着它们需要能够扩展大小,以使它们的大小相等。在这种情况下,v 是您感兴趣的向量并且是第一个参数 - 请注意它是转置的。第二个参数是一个从 1 到 n 的向量。现在将发生的情况是列向量vreplicated / expands 的值与n 一样多,第二个向量被复制的行数为有v。然后我们在这两个数组之间做一个eq/equals 运算符。实际上,这个扩展矩阵的第一列全为 1,第二列全为 2,直到n。通过在这两个矩阵之间执行eq,您实际上可以确定v 中的哪些值等于相应的列索引。


    这里是每个功能的详细时间测试和细分。我将每个实现放入一个单独的函数中,并且我还让n=max(v) 让 Luis 的第一个代码能够工作。我使用timeit 为每个函数计时:

    function timing_binary
    
    n = 10000;
    v = randi(1000,n,1);
    m = numel(v);
    
        function luis_func()
        M1 = full(sparse(1:m,v,1));       
        end
    
        function luis_func2()
        %m = numel(v);
        %n = 3; %// or compute n automatically as n = max(v);
        M2 = zeros(m, n);
        M2((1:m).' + (v-1)*m) = 1;      
        end
    
        function ray_func()
        M3 = bsxfun(@eq, v, 1:n);
        end
    
        function op_func()
        M4= ones(1,m)'*[1:n] == v * ones(1,n);
        end
    
    t1 = timeit(@luis_func);
    t2 = timeit(@luis_func2);
    t3 = timeit(@ray_func);
    t4 = timeit(@op_func);
    
    fprintf('Luis Mendo - Sparse: %f\n', t1);
    fprintf('Luis Mendo - Indexing: %f\n', t2);
    fprintf('rayryeng - bsxfun: %f\n', t3);
    fprintf('OP: %f\n', t4);
    
    
    end
    

    此测试假设 n = 10000 和向量 v 是一个 10000 x 1 的向量,包含从 1 到 1000 的随机分布的整数。顺便说一句,我不得不修改 Luis 的第二个函数,以便索引能够按照添加的要求工作兼容维度的向量。

    运行这段代码,我们得到:

    >> timing_binary
    Luis Mendo - Sparse: 0.015086
    Luis Mendo - Indexing: 0.327993
    rayryeng - bsxfun: 0.040672
    OP: 0.841827
    

    Luis Mendo 的 sparse 代码获胜(如我所料),然后是 bsxfun,然后是索引,然后是您提出的使用矩阵运算的方法。时间以秒为单位。

    【讨论】:

    • 天哪,我写的是完全相同的答案哈哈,我肯定打字太慢了!
    • @Benoit_11 - 哈哈抱歉:)
    • @LuisMendo - 谢谢! :D 我不得不稍微改变一下,因为我读的太快了。
    • @LuisMendo 不同意你的观点。 .' 将执行转置,而不管数组是实数还是复数。单独执行 ' 将执行 complex 转置。我使用点是因为我明确地想明确这一点。不过,这更像是一种风格选择。在你的情况下,你没有想象的组件,所以你可以使用或者,但我习惯使用.'。不使用它已经在@$$ 中咬了我几次......所以我只是习惯使用它。
    • @gciriani 我总是建议:当你只想转置时使用.'!以下是使用' 导致的错误的两个示例,而您的意思是.'stackoverflow.com/questions/22258444/… stackoverflow.com/questions/23509241/…
    【解决方案2】:

    假设n等于max(v),则可以使用sparse

    v = [1,1,3,2];
    M = full(sparse(1:numel(v),v,1));
    

    sparse 所做的是使用第一个参数作为行索引,第二个作为列索引,第三个作为矩阵值来构建一个稀疏矩阵。然后将其转换为带有full 的完整矩阵。


    另一种方法是定义最初包含零的矩阵,然后使用linear indexing 填充零:

    v = [1,1,3,2];
    m = numel(v);
    n = 3; %// or compute n automatically as n = max(v);
    M = zeros(m, n);
    M((1:m) + (v-1)*m) = 1;
    

    【讨论】:

      【解决方案3】:

      我想我也找到了一种方法,如果有人能告诉我显示的哪种方法对于非常大的向量和矩阵更快,那就太好了。我想到的附加方法如下

      M= ones(1,m)'*[1:n] == v * ones(1,n)
      

      【讨论】:

        猜你喜欢
        • 2019-05-02
        • 2010-12-28
        • 1970-01-01
        • 1970-01-01
        • 2013-05-26
        • 2022-01-23
        • 1970-01-01
        • 2015-06-01
        • 2020-04-21
        相关资源
        最近更新 更多