【问题标题】:MATLAB: Multiply 2D matrix with 3D matrix within cell arraysMATLAB:在单元格数组中将 2D 矩阵与 3D 矩阵相乘
【发布时间】:2017-09-23 19:58:16
【问题描述】:

我有一个恒定的二维双矩阵mat1。我还有一个 2D 单元格数组 mat2,其中每个单元格都包含一个 2D 或 3D 双矩阵。这些双精度矩阵的行数和列数与mat1 相同。我需要将mat1 与mat2 内的每个双矩阵的每个切片点乘(。*)。结果需要是另一个元胞数组results,其大小与mat2 相同,其中包含的双精度矩阵的大小必须等于mat2 的双精度矩阵。

这是我生成 mat1 和 mat2 的代码,用于说明目的。我在应该发生乘法的地方挣扎。

rowCells = 5;
colCells = 3;
rowTimeSeries = 300;
colTimeSeries = 5;
slices = [1;10];

% Create 2D double matrix
mat1 = rand(rowTimeSeries, colTimeSeries);

% Create 2D cell matrix comprisiong 2D and/or 3D double matrices
mat2 = cell(rowCells,colCells);

for c = 1:colCells
    for r = 1:rowCells
        slice = randsample(slices, 1, true);
        mat2{r,c} = rand(rowTimeSeries, colTimeSeries, slice);
    end
end

% Multiply (.*) mat1 with mat2 (every slice)

results = cell(rowCells,colCells);

for c = 1:colCells
    for r = 1:rowCells
        results{r,c} = ... % I am struggling here!!!
    end
end

【问题讨论】:

    标签: matlab multidimensional-array cell-array multiplication


    【解决方案1】:

    您可以使用bsxfun 来消除对自定义函数multiply2D3D 的需求,它的工作方式类似!更新代码:

    results = cell(rowCells,colCells);
    for c = 1:colCells
        for r = 1:rowCells
            results{r,c} = bsxfun(@times, mat1, mat2{r,c});
        end
    end
    

    这适用于 2D 和 3D 矩阵,其中每个“切片”中的行数和列数都相同,因此它应该适用于您的情况。


    您也不需要分别循环遍历元胞数组的行和列。这个循环的迭代次数是一样的,但是是一个循环而不是两个,所以代码精简了一点:

    results = cell(size(mat2));
    for n = 1:numel(mat2)   % Loop over every element of mat2. numel(mat2) = rowCells*colCells
        results{n} = bsxfun(@times, mat1, mat2{n});
    end
    

    【讨论】:

      【解决方案2】:

      我的答案与 Wolfie 几乎完全相同,但他比我更胜一筹。

      无论如何,这里有一个我认为稍微好一点的班轮:

      nR = rowCells; % Number of Rows
      nC = colCells; % Number of Cols
      results = arrayfun(@(I) bsxfun(@times, mat1, mat2{I}), reshape(1:nR*nC,[],nC), 'un',0);
      

      这使用arrayfun 执行循环索引,使用bsxfun 执行乘法运算。


      一些优点

      1) 在arrayfun 中指定'UniformOutput' ('un') 返回一个元胞数组,因此results 变量也是一个元胞数组并且不需要初始化(与使用循环相比)。

      2) 索引的维度决定了results在输出时的维度,所以它们可以匹配你喜欢的。

      3) 单行可以直接用作函数的输入参数。

      缺点

      1) Can run slower 比使用 for 循环正如 Wolfie 在 cmets 中指出的那样。

      【讨论】:

      • 好答案/代码雅各布,我没想过使用arrayfun!或许也值得注意一个缺点。我刚刚做了一些测试,似乎使用arrayfun 比仅循环输入各种尺寸的速度要慢。请参阅此 SO 问题,该问题的最佳答案深入探讨了 arrayfun 的开销和速度问题:stackoverflow.com/questions/12522888/…
      • @JacobD 您的代码也运行良好,但是,我更喜欢 Wolfie 的解决方案。对我来说主要的优势是代码更容易阅读和理解。但这是我个人的看法。
      • @Wolfie 好点,我忘了用arrayfun 添加一些关于速度/开销的内容。对于小尺寸,这可能不是问题,但按比例放大是的,肯定会浪费一些时间。我想在这种情况下使用arrayfun 或for 循环之间的速度差异很大程度上取决于“内部”和“外部”矩阵大小的比率(Cells 与TimeSeries 就像OP所说的那样)。
      • @Andi 这完全可以理解,for 循环经常提供更容易阅读/理解的代码。但是,在 Matlab 中,for 循环通常会减慢计算速度,因此可能首选矩阵操作。该解决方案可能更针对这一点,即使由于arrayfun 而速度较慢,但​​它至少显示了没有for 循环的解决方案。
      【解决方案3】:

      我想出的一个解决方案是将 2D 与 3D 矩阵的乘法外包到一个函数中。但是,我很想知道这是否是解决此问题的最有效方法?

      rowCells = 5;
      colCells = 3;
      rowTimeSeries = 300;
      colTimeSeries = 5;
      slices = [1;10];
      
      % Create 2D double matrix
      mat1 = rand(rowTimeSeries, colTimeSeries);
      
      % Create 2D cell matrix comprisiong 2D and/or 3D double matrices
      mat2 = cell(rowCells,colCells);
      
      for c = 1:colCells
          for r = 1:rowCells
              slice = randsample(slices, 1, true);
              mat2{r,c} = rand(rowTimeSeries, colTimeSeries, slice);
          end
      end
      
      % Multiply (.*) mat1 with mat2 (every slice)
      
      results = cell(rowCells,colCells);
      
      for c = 1:colCells
          for r = 1:rowCells
              results{r,c} = multiply2D3D(mat1, mat2{r,c});
          end
      end
      
      
      function vout = multiply2D3D(mat2D, mat3D)
      %MULTIPLY2D3D multiplies a 2D double matrix with every slice of a 3D
      % double matrix.
      %
      % INPUTs:
      %   mat2D:
      %   2D double matrix
      %
      %   mat3D:
      %   3D double matrix where the third dimension is equal or greater than 1.
      %
      % OUTPUT:
      %   vout:
      %   3D double matrix with the same size as mat3D. Every slice in vout
      %   is the result of a multiplication of mat2D with every individual slice
      %   of mat3D.
      
      [rows, cols,  slices] = size(mat3D);
      vout = zeros(rows, cols, slices);
      
      for s = 1 : slices
          vout(:,:,s) = mat2D .* mat3D(:,:,s);
      end
      
      end
      

      【讨论】:

        猜你喜欢
        • 2016-12-11
        • 1970-01-01
        • 2012-01-31
        • 1970-01-01
        • 2021-05-25
        • 1970-01-01
        • 2015-01-24
        • 2018-07-09
        相关资源
        最近更新 更多