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

时间:2015-08-30 14:46:02

标签: arrays matlab matrix cell-array

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

enter image description here

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

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

我该如何解决这个问题?我通常使用这种形式处理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);

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

2 个答案:

答案 0 :(得分: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.

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.

%// 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

答案 1 :(得分:0)

蛮力方法:

[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};

我不知道您的实际结构是什么样的,但这适用于使用以下步骤设置的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