从3D单元阵列转换为一组2D矩阵

时间:2022-01-16 11:59:47

I have a 3D-cell array designated as A{s,i,h}, serving as a store for large amounts of numerical data during a nested-loop portion of my script. Some of the cell entries will be blank [ ], whilst the rest consist of numbers - either singular or in arrays (1 x 10 double etc.):

我有一个3D单元格数组,指定为A {s,i,h},在我的脚本的嵌套循环部分期间用作存储大量数值数据的存储。一些单元格条目将为空白[],而其余单元格由数字组成 - 单数或数组(1 x 10双等):

从3D单元阵列转换为一组2D矩阵

I want to convert this cell array to a set of 2D matrices.

我想将这个单元格数组转换为一组2D矩阵。

Specifically, one separate matrix for each value of h (h is always equal 1:3) and one column in each matrix for every value of s. Each column will contain all the numerical data combined - it does not need to be separated by i.

具体地,对于h的每个值,每个值的一个单独的矩阵(h总是等于1:3),并且对于s的每个值,每个矩阵中有一列。每列将包含所有组合的数值数据 - 它不需要由i分隔。

How can I go about this? I ordinarily deal with 3D-cell arrays in this form to produce separate matrices (one for each value of h) using something like this:

我怎么能这样做?我通常使用这种形式处理3D单元阵列,以使用以下内容生成单独的矩阵(每个h值一个):

lens = sum(cellfun('length',reshape(A,[],size(A,3))),1);
max_length = max(lens);
mat = zeros(max_length,numel(lens));
mask = bsxfun(@le,[1:max_length]',lens);
mat(mask) = [A{:}];
mat(mat==0) = NaN;
mat = sort(mat*100);
Matrix1 = mat(~isnan(mat(:,1)),1);
Matrix2 = mat(~isnan(mat(:,2)),2);
Matrix3 = mat(~isnan(mat(:,3)),3);

However in this instance, each matrix had only a single column. I'm have trouble adding multiple columns to each output matrix.

然而,在这种情况下,每个矩阵只有一列。我在为每个输出矩阵添加多个列时遇到问题。

2 个解决方案

#1


2  

1. Result in the form of a cell array of matrices (as requested)

Here's one possible approach. I had to use one for loop. However, the loop can be easily avoided if you accept a 3D-array result instead of a cell array of 2D-arrays. See second part of the answer.

这是一种可能的方法。我不得不使用一个for循环。但是,如果接受3D阵列结果而不是2D阵列的单元阵列,则可以轻松避免循环。请参阅答案的第二部分。

If you follow the comments in the code and inspect the result of each step, it's straightforward to see how it works.

如果您按照代码中的注释并检查每个步骤的结果,则可以直接了解它的工作原理。

%// Example data
A(:,:,1) = { 1:2, 3:5, 6:9; 10 11:12 13:15 };
A(:,:,2) = { 16:18, 19:22, 23; 24:28, [], 29:30 };

%// Let's go
[S, I, H] = size(A);
B = permute(A, [2 1 3]); %// permute rows and columns
B = squeeze(mat2cell(B, I, ones(1, S), ones(1, H))); %// group each col of B into a cell...
B = cellfun(@(x) [x{:}], B, 'uniformoutput', false); %// ...containing a single vector
t = cellfun(@numel, B); %// lengths of all columns of result
result = cell(1,H); %// preallocate
for h = 1:H
    mask = bsxfun(@le, (1:max(t(:,h))), t(:,h)).'; %'// values of result{h} to be used
    result{h} = NaN(size(mask)); %// unused values will be NaN
    result{h}(mask) = [B{:,h}]; %// fill values for matrix result{h}
end

Result in this example:

结果在这个例子中:

A{1,1,1} =
     1     2
A{2,1,1} =
    10
A{1,2,1} =
     3     4     5
A{2,2,1} =
    11    12
A{1,3,1} =
     6     7     8     9
A{2,3,1} =
    13    14    15
A{1,1,2} =
    16    17    18
A{2,1,2} =
    24    25    26    27    28
A{1,2,2} =
    19    20    21    22
A{2,2,2} =
     []
A{1,3,2} =
    23
A{2,3,2} =
    29    30

result{1} =
     1    10
     2    11
     3    12
     4    13
     5    14
     6    15
     7   NaN
     8   NaN
     9   NaN
result{2} =
    16    24
    17    25
    18    26
    19    27
    20    28
    21    29
    22    30
    23   NaN

2. Result in the form of 3D array

As indicated above, using a 3D array to store the result permits avoiding loops. In the code below, the last three lines replace the loop used in the first part of the answer. The rest of the code is the same.

如上所述,使用3D阵列存储结果允许避免循环。在下面的代码中,最后三行替换了答案第一部分中使用的循环。其余代码是相同的。

%// Example data
A(:,:,1) = { 1:2, 3:5, 6:9; 10 11:12 13:15 };
A(:,:,2) = { 16:18, 19:22, 23; 24:28, [], 29:30 };

%// Let's go
[S, I, H] = size(A);
B = permute(A, [2 1 3]); %// permute rows and columns
B = squeeze(mat2cell(B, I, ones(1, S), ones(1, H))); %// group each col of B into a cell...
B = cellfun(@(x) [x{:}], B, 'uniformoutput', false); %// ...containing a single vector
t = cellfun(@numel, B); %// lengths of all columns of result
mask = bsxfun(@le, (1:max(t(:))).', permute(t, [3 1 2])); %'// values of result to be used
result = NaN(size(mask)); %// unused values will be NaN
result(mask) = [B{:}]; %// fill values

This gives (compare with result of the first part):

这给出(与第一部分的结果比较):

>> result
result(:,:,1) =
     1    10
     2    11
     3    12
     4    13
     5    14
     6    15
     7   NaN
     8   NaN
     9   NaN
result(:,:,2) =
    16    24
    17    25
    18    26
    19    27
    20    28
    21    29
    22    30
    23   NaN
   NaN   NaN

#2


0  

Brute force approach:

蛮力方法:

[num_s, num_i, num_h] = size(A);
cellofmat = cell(num_h,1);
for matrix = 1:num_h
    sizemat = max(cellfun(@numel, A(:,1,matrix)));
    cellofmat{matrix} = nan(sizemat, num_s);
    for column = 1:num_s
        lengthcol = length(A{column, 1, matrix});
        cellofmat{matrix}(1:lengthcol, column) = A{column, 1,matrix};
    end
end
Matrix1 = cellofmat{1};
Matrix2 = cellofmat{2};
Matrix3 = cellofmat{3};

I don't know what your actual structure looks like but this works for A that is setup using the following steps.

我不知道你的实际结构是什么样的,但这适用于使用以下步骤设置的A.

A = cell(20,1,3);
for x = 1:3
    for y = 1:20
        len = ceil(rand(1,1) * 10);
        A{y,1,x} = rand(len, 1);
    end
end

#1


2  

1. Result in the form of a cell array of matrices (as requested)

Here's one possible approach. I had to use one for loop. However, the loop can be easily avoided if you accept a 3D-array result instead of a cell array of 2D-arrays. See second part of the answer.

这是一种可能的方法。我不得不使用一个for循环。但是,如果接受3D阵列结果而不是2D阵列的单元阵列,则可以轻松避免循环。请参阅答案的第二部分。

If you follow the comments in the code and inspect the result of each step, it's straightforward to see how it works.

如果您按照代码中的注释并检查每个步骤的结果,则可以直接了解它的工作原理。

%// Example data
A(:,:,1) = { 1:2, 3:5, 6:9; 10 11:12 13:15 };
A(:,:,2) = { 16:18, 19:22, 23; 24:28, [], 29:30 };

%// Let's go
[S, I, H] = size(A);
B = permute(A, [2 1 3]); %// permute rows and columns
B = squeeze(mat2cell(B, I, ones(1, S), ones(1, H))); %// group each col of B into a cell...
B = cellfun(@(x) [x{:}], B, 'uniformoutput', false); %// ...containing a single vector
t = cellfun(@numel, B); %// lengths of all columns of result
result = cell(1,H); %// preallocate
for h = 1:H
    mask = bsxfun(@le, (1:max(t(:,h))), t(:,h)).'; %'// values of result{h} to be used
    result{h} = NaN(size(mask)); %// unused values will be NaN
    result{h}(mask) = [B{:,h}]; %// fill values for matrix result{h}
end

Result in this example:

结果在这个例子中:

A{1,1,1} =
     1     2
A{2,1,1} =
    10
A{1,2,1} =
     3     4     5
A{2,2,1} =
    11    12
A{1,3,1} =
     6     7     8     9
A{2,3,1} =
    13    14    15
A{1,1,2} =
    16    17    18
A{2,1,2} =
    24    25    26    27    28
A{1,2,2} =
    19    20    21    22
A{2,2,2} =
     []
A{1,3,2} =
    23
A{2,3,2} =
    29    30

result{1} =
     1    10
     2    11
     3    12
     4    13
     5    14
     6    15
     7   NaN
     8   NaN
     9   NaN
result{2} =
    16    24
    17    25
    18    26
    19    27
    20    28
    21    29
    22    30
    23   NaN

2. Result in the form of 3D array

As indicated above, using a 3D array to store the result permits avoiding loops. In the code below, the last three lines replace the loop used in the first part of the answer. The rest of the code is the same.

如上所述,使用3D阵列存储结果允许避免循环。在下面的代码中,最后三行替换了答案第一部分中使用的循环。其余代码是相同的。

%// Example data
A(:,:,1) = { 1:2, 3:5, 6:9; 10 11:12 13:15 };
A(:,:,2) = { 16:18, 19:22, 23; 24:28, [], 29:30 };

%// Let's go
[S, I, H] = size(A);
B = permute(A, [2 1 3]); %// permute rows and columns
B = squeeze(mat2cell(B, I, ones(1, S), ones(1, H))); %// group each col of B into a cell...
B = cellfun(@(x) [x{:}], B, 'uniformoutput', false); %// ...containing a single vector
t = cellfun(@numel, B); %// lengths of all columns of result
mask = bsxfun(@le, (1:max(t(:))).', permute(t, [3 1 2])); %'// values of result to be used
result = NaN(size(mask)); %// unused values will be NaN
result(mask) = [B{:}]; %// fill values

This gives (compare with result of the first part):

这给出(与第一部分的结果比较):

>> result
result(:,:,1) =
     1    10
     2    11
     3    12
     4    13
     5    14
     6    15
     7   NaN
     8   NaN
     9   NaN
result(:,:,2) =
    16    24
    17    25
    18    26
    19    27
    20    28
    21    29
    22    30
    23   NaN
   NaN   NaN

#2


0  

Brute force approach:

蛮力方法:

[num_s, num_i, num_h] = size(A);
cellofmat = cell(num_h,1);
for matrix = 1:num_h
    sizemat = max(cellfun(@numel, A(:,1,matrix)));
    cellofmat{matrix} = nan(sizemat, num_s);
    for column = 1:num_s
        lengthcol = length(A{column, 1, matrix});
        cellofmat{matrix}(1:lengthcol, column) = A{column, 1,matrix};
    end
end
Matrix1 = cellofmat{1};
Matrix2 = cellofmat{2};
Matrix3 = cellofmat{3};

I don't know what your actual structure looks like but this works for A that is setup using the following steps.

我不知道你的实际结构是什么样的,但这适用于使用以下步骤设置的A.

A = cell(20,1,3);
for x = 1:3
    for y = 1:20
        len = ceil(rand(1,1) * 10);
        A{y,1,x} = rand(len, 1);
    end
end