MATLAB:在元胞数组中将 2D 矩阵与 3D 矩阵相乘

MATLAB: Multiply 2D matrix with 3D matrix within cell arrays

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

这是我生成 mat1mat2 的代码,用于说明目的。我在应该进行乘法运算的地方苦苦挣扎。

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

我想到的一个解决方案是将 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

您可以使用 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

这将适用于行数和列数在每个 "slices" 中相同的 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

我的答案几乎与 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 to perform the loop indexing and bsxfun 进行乘法运算。


几个优点

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

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

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

劣势

1) Can run slower 而不是像 Wolfie 在评论中指出的那样使用 for 循环。