【问题标题】:How to create a sparse matrix in MATLAB given the locations of non-zero elements给定非零元素的位置,如何在 MATLAB 中创建稀疏矩阵
【发布时间】:2012-09-21 10:34:46
【问题描述】:

我需要在 MATLAB 中创建具有以下要求的矩阵。给定一个向量v,比如[1,2,2,1,3,5,1],我需要形成一个矩阵:

[1 0 0 1 0 0 1;
 0 1 1 0 0 0 0;
 0 0 0 0 1 0 0;
 0 0 0 0 0 0 0;
 0 0 0 0 0 1 0]

即矩阵的ith 列在v[i] 行仅包含一个非零元素(单个1)。如何避免循环并以有效的方式做到这一点?

【问题讨论】:

  • 这并不能回答问题,但以防万一您没有意识到:跨输出矩阵列的单个循环(这使得解决问题变得微不足道)应该几乎同样有效如果您只使用一个 CPU,作为完全矢量化的解决方案,并且如果您有多个 CPU,它仍然会表现得非常好。一个很好的解释为什么是here

标签: matlab matrix


【解决方案1】:

这与在神经网络分配中创建目标向量所需的步骤非常相似(第 5 周 - Andrew NG ML 课程中的手写数字识别)。我们必须为单个训练输出创建一个 10 X 1 大小的向量,例如输出 y。如果 y 中的第 i 个训练输出为 2,则向量化后的第 i 个输出为 [0 1 0 0 0 0 0 0 0 0]'。 因此,对于 5000 个训练示例,我们需要 5000 个向量。

废话不多说,代码如下:


>> v =  [1,2,2,1,3,5,1];
>> v_vec = (1:5)==v';
>> v_vec
v_vec =

  1  0  0  0  0
  0  1  0  0  0
  0  1  0  0  0
  1  0  0  0  0
  0  0  1  0  0
  0  0  0  0  1
  1  0  0  0  0

>> v_vec'
ans =

  1  0  0  1  0  0  1
  0  1  1  0  0  0  0
  0  0  0  0  1  0  0
  0  0  0  0  0  0  0
  0  0  0  0  0  1  0

v_vec' 是所需的输出。 一个有用的链接:https://www.ee.columbia.edu/~marios/matlab/Matlab%20Tricks.pdf

【讨论】:

    【解决方案2】:

    其他人指出循环在这里很好。我会指出稀疏的要好得多。你的矩阵是稀疏的,非常稀疏,所以使用稀疏的能力来解决这个问题,并且在矩阵很大的情况下节省大量的存储空间。

    N = 3000;
    v = ceil(rand(1,3000)*3000);
    
    tic
    A = zeros(N,N);
    for i = 1:N
      A(v(i),i) = 1;
    end
    toc
    Elapsed time is 0.069082 seconds.
    
    tic
    B = sparse(v,1:N,1,N,N);
    toc
    Elapsed time is 0.001308 seconds.
    

    所以如果矩阵很大的话,时间上就会有很大的差异。

    空间怎么样?

    whos A B
      Name         Size                 Bytes  Class     Attributes
    
      A         3000x3000            72000000  double              
      B         3000x3000               72008  double    sparse    
    

    这些矩阵在其他方面是相同的。

    sum(sum(abs(A - B)))
    ans =
         0
    

    稀疏矩阵占用的空间很小,您可以像使用任何其他矩阵一样使用它。

    使用 MATLAB 的功能。

    【讨论】:

      【解决方案3】:
      >> v =  [1,2,2,1,3,5,1];
      >> a = zeros(max(v), length(v));
      >> a((0 : size(a, 1) : numel(a) - 1) + v) = 1
      
      a =
      
           1     0     0     1     0     0     1
           0     1     1     0     0     0     0
           0     0     0     0     1     0     0
           0     0     0     0     0     0     0
           0     0     0     0     0     1     0
      

      【讨论】:

        【解决方案4】:
        m = max(v);
        n = length(v);
        M = zeros(m, n);
        M([0:(n-1)]*m + v) = 1;
        

        【讨论】:

        • 我想你的意思是最后一行是M([0:n-1]*m + v) = 1;
        【解决方案5】:

        首先,我必须给出我的标准免责声明,尽管普遍认为在 MATLAB 中通常应该避免循环,但在 MATLAB 的现代版本中,循环实际上变得更加高效,这在很大程度上要归功于 JIT 加速器.因此,当然,对您的代码进行基准测试以确定循环是否真的是瓶颈。

        也就是说,我对如何在没有循环的情况下解决这个问题的第一个想法是索引到一个单位矩阵(如下所示)。

        identityMatrix = eye(max(v(:)));
        result = identityMatrix(:,v);
        

        我认为这是一个不错的、干净的解决方案;但是,我不一定知道它比使用循环明显更有效率。作为比较,我使用循环实现了以下解决方案:

        numRows = max(v(:));
        numCols = length(v);
        result = zeros(numRows,numCols);
        
        for i=1:numCols
            result(v(i),i) = 1;
        end
        

        根据我的测试运行,对于v 不是很长的情况,看起来顶级(无循环)解决方案通常更快。但是,当 v 包含许多元素(例如 >100)时,我实际上看到 loop 解决方案击败替代方案的平均时间。

        【讨论】:

        • @woodchips - 我没有想到这一点,但现在你指出这似乎是sparse 的完美使用。感谢您的洞察力。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-06-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多