2017-07-31 114 views
4

的阵列我想构造一个函数MATLAB:从多维数组中删除子阵列到那些

[B, ind] = extract_ones(A) 

其去除一些子阵列从二进制数组任意尺寸A,例如那剩下的阵列B是最大的阵列,只有1,我也想记录在ind那里的每个1在B来自。


实施例1

假设是如图

A = 
1 1 0 0 0 1 
1 1 1 0 1 1 
0 0 0 1 0 1 
1 1 0 1 0 1 
1 1 0 1 0 1 
1 1 1 1 1 1 

中取出后的2 d阵列A(3,:)A(:, 3:5),我们有输出B

B = 
1 1 1 
1 1 1 
1 1 1 
1 1 1 
1 1 1 

这是最大的阵列,只有通过删除行和列的A。 作为15层1的B的分别对应于

A(1,1) A(1,2) A(1,6) 
A(2,1) A(2,2) A(2,6) 
A(4,1) A(4,2) A(4,6) 
A(5,1) A(5,2) A(5,6) 
A(6,1) A(6,2) A(6,6) 

,或者等效

A(1) A(7) A(31) 
A(2) A(8) A(32) 
A(4) A(10) A(34) 
A(5) A(11) A(35) 
A(6) A(12) A(36) 

所以,输出IND看起来像(当然IND的形状并不重要):

ind = [1 2 4 5 6 7 8 10 11 12 31 32 34 35 36] 

实施例2

如果输入

A = ones(6,3,4,3); 
A(2,2,2,2) = 0; 
A(4,1,3,3) = 0; 
A(1,1,4,2) = 0; 
A(1,1,4,1) = 0; 

构造接着,通过删除包含A(2,2,2,2)中,A的最小长方体(4,1 ,3,3),A(1,1,4,3)和A(1,1,4,1),删除这些项

A(2,:,:,:) 
A(:,1,:,:) 

然后将剩余的阵列之后即会组成只有1。和B中的那些对应于

A([1,3:6],2:3,1:4,1:3) 

因此,输出IND列出了标变换成指数,即

ind = [7 9 10 11 12 13 15 16 17 18 25 27 28 29 30 31 33 34 35 36 43 45 46 47 48 49 51 52 53 54 61 63 64 65 66 67 69 70 71 72 79 81 82 83 84 85 87 88 89 90 97 99 100 101 102 103 105 106 107 108 115 117 118 119 120 121 123 124 125 126 133 135 136 137 138 139 141 142 143 144 151 153 154 155 156 157 159 160 161 162 169 171 172 173 174 175 177 178 179 180 187 189 190 191 192 193 195 196 197 198 205 207 208 209 210 211 213 214 215 216] 

根据需要数组如上所述加工是在8 d,并应处理多次,所以任何人都可以给我就如何撰写程序完成这个任务快速意见?


我的工作至今[增加了凌晨2点(GMT-4),2017年8月2日]

我的想法是,我删除子阵列,由零壹所占比例最大一。这里是到目前为止我的工作:

Inds = reshape(1:numel(A),size(A)); % Keep track on which 1's survive. 
cont = true; 

while cont 
    sz = size(A); 
    zero_percentage = 0; 
    Test_location = []; 

    % This nested for loops are for determining which sub-array of A has the 
    % maximum proportion of zeros. 
    for J = 1 : ndims(A) 
     for K = 1 : sz(J) 
      % Location is in the form of (_,_,_,...,_) 
      % where the J-th blank is K, the other blanks are colons. 
      Location = strcat('(',repmat(':,',1,(J-1)),int2str(K),repmat(',:',1,(ndims(A)-J)),')'); 
      Test_array = eval(strcat('A',Location,';')); 
      N = numel(Test_array); 
      while numel(Test_array) ~= 1 
       Test_array = sum(Test_array); 
      end 
      test_zero_percentage = 1 - (Test_array/N); 
      if test_zero_percentage > zero_percentage 
       zero_percentage = test_zero_percentage; 
       Test_location = Location; 
      end 
     end 
    end 

    % Delete the array with maximum proportion of zeros 
    eval(strcat('A',Test_location,'= [];')) 
    eval(strcat('Inds',Test_location,'= [];')) 

    % Determine if there are still zeros in A. If there are, continue the while loop. 
    cont = A; 
    while numel(cont) ~= 1 
     cont = prod(cont); 
    end 
    cont = ~logical(cont); 
end 

但我遇到了两个问题:

1)这可能是效率不高,要检查所有阵列中的所有子维度一个接一个。

2)结果不包含最多数量的矩形元素。例如,我用一个2维二进制数组测试我的工作

A = 
0  0  0  1  1  0 
0  1  1  0  1  1 
1  0  1  1  1  1 
1  0  0  1  1  1 
0  1  1  0  1  1 
0  1  0  0  1  1 
1  0  0  0  1  1 
1  0  0  0  0  0 

它应该返回我的结果作为

B = 
1  1 
1  1 
1  1 
1  1 
1  1 
1  1 

Inds = 
34 42 
35 43 
36 44 
37 45 
38 46 
39 47 

但是,相反,代码返回我这样的:

B = 
1  1  1 
1  1  1 
1  1  1 

Inds = 
10 34 42 
13 37 45 
14 38 46 

*我的工作至今2加在中午12时(GMT-4),2017年8月2日]

这是我目前的修正案。这可能不会提供最佳结果。 这可能会给这个问题提供一个相当不错的近似值,并且这不会给空虚的。但我仍然希望有更好的解决方案。

function [B, Inds] = Finding_ones(A) 

Inds = reshape(1:numel(A),size(A)); % Keep track on which 1's survive. 
sz0 = size(A); 
cont = true; 

while cont 
    sz = size(A); 
    zero_percentage = 0; 
    Test_location = []; 

    % This nested for loops are for determining which sub-array of A has the 
    % maximum proportion of zeros. 
    for J = 1 : ndims(A) 
     for K = 1 : sz(J) 
      % Location is in the form of (_,_,_,...,_) 
      % where the J-th blank is K, the other blanks are colons. 
      Location = strcat('(',repmat(':,',1,(J-1)),int2str(K),repmat(',:',1,(ndims(A)-J)),')'); 
      Test_array = eval(strcat('A',Location,';')); 
      N = numel(Test_array); 
      Test_array = sum(Test_array(:)); 

      test_zero_percentage = 1 - (Test_array/N); 
      if test_zero_percentage > zero_percentage 
       eval(strcat('Testfornumel = numel(A',Location,');')) 
       if Testfornumel < numel(A) % Preventing the A from being empty 
        zero_percentage = test_zero_percentage; 
        Test_location = Location; 
       end 
      end 
     end 
    end 

    % Delete the array with maximum proportion of zeros 
    eval(strcat('A',Test_location,'= [];')) 
    eval(strcat('Inds',Test_location,'= [];')) 

    % Determine if there are still zeros in A. If there are, continue the while loop. 
    cont = A; 
    while numel(cont) ~= 1 
     cont = prod(cont); 
    end 
    cont = ~logical(cont); 
end 

B = A; 

% command = 'i1, i2, ... ,in' 
% here, n is the number of dimansion of A. 
command = 'i1'; 
for J = 2 : length(sz0) 
    command = strcat(command,',i',int2str(J)); 
end 

Inds = reshape(Inds,numel(Inds),1); %#ok<NASGU> 
eval(strcat('[',command,'] = ind2sub(sz0,Inds);')) 

% Reform Inds into a 2-D matrix, which each column indicate the location of 
% the 1 originated from A. 
Inds = squeeze(eval(strcat('[',command,']'))); 
Inds = reshape(Inds',length(sz0),numel(Inds)/length(sz0)); 

end 

回答

1

第二次尝试:从种子点开始,尝试在所有维度上增长矩阵。结果是矩阵中的起点和终点。

function [ res ] = seed_grow(A) 
if ~islogical(A),A=(A==1);end 
if ~any(A(:)),res={};end 
go = true; 
dims=size(A); 
ind = cell([1 length(dims)]); %cell to store find results 
seeds=A;maxmat=0; 
while go %main loop to remove all posible seeds 
    [ind{:}]=find(seeds,1,'first'); 
    S = [ind{:}]; %the seed 
    St = [ind{:}]; %the end of the seed 
    go2=true; 
    val_dims=1:length(dims); 
    while go2 %loop to grow each dimension 
     D=1; 
     while D<=length(val_dims) %add one to each dimension 
      St(val_dims(D))=St(val_dims(D))+1; 
      I={}; 
      for ct = 1:length(S),I{ct}=S(ct):St(ct);end %generate indices 
      if St(val_dims(D))>dims(val_dims(D)) 
       res=false;%outside matrix 
      else 
       res=A(I{:}); 
      end 
      if ~all(res(:)) %invalid addition to dimension 
       St(val_dims(D))=St(val_dims(D))-1; %undo 
       val_dims(D)=[]; D=D-1; %do not try again 
       if isempty(val_dims),go2=false;end %end of growth 
      end 
      D=D+1; 
     end 
    end 
    %evaluate the result 
    mat = prod((St+1)-S); %size of matrix 
    if mat>maxmat 
     res={S,St}; 
     maxmat=mat; 
    end 
    %tried to expand, now remove seed option 
    for ct = 1:length(S),I{ct}=S(ct):St(ct);end %generate indices 
    seeds(I{:})=0;  
    if ~any(seeds),go=0;end 
end 
end 

我测试了使用矩阵:

A = [0  0  0  1  1  0 
0  1  1  0  1  1 
1  0  1  1  1  1 
1  0  0  1  1  1 
0  1  1  0  1  1 
0  1  0  0  1  1 
1  0  0  0  1  1 
1  0  0  0  0  0]; 
[ res ] = seed_grow(A); 
for ct = 1:length(res),I{ct}=res{1}(ct):res{2}(ct);end %generate indices 
B=A(I{:}); 
idx = reshape(1:numel(A),size(A)); 
idx = idx(I{:}); 

,并得到想要的结果:

B = 

    1  1 
    1  1 
    1  1 
    1  1 
    1  1 
    1  1 


idx = 

    34 42 
    35 43 
    36 44 
    37 45 
    38 46 
    39 47 
2

这似乎是一个难以解决的问题,因为删除顺序在最终结果中可能会发生很大的变化。如果在第一个示例中,您首先删除包含0的所有列,则不会得到期望的结果。

下面的代码会删除最多为零的行或列,并一直保持到只有一行为止。它跟踪被删除的行和列以找到其余列的索引。

function [B,ind] = extract_ones(A) 
if ~islogical(A),A=(A==1);end 
if ~any(A(:)),B=[];ind=[];return,end 
B=A;cdel=[];rdel=[]; 
while ~all(B(:)) 
    [I,J] = ind2sub(size(B),find(B==0)); 
    ih=histcounts(I,[0.5:1:size(B,1)+0.5]); %zero's in rows 
    jh=histcounts(J,[0.5:1:size(B,2)+0.5]); %zero's in columns 
    if max(ih)>max(jh) 
     idxr=find(ih==max(ih),1,'first'); 
     B(idxr,:)=[]; 
     %store deletion 
     rdel(end+1)=idxr+sum(rdel<=idxr); 
    elseif max(ih)==max(jh) 
     idxr=find(ih==max(ih),1,'first'); 
     idxc=find(jh==max(jh),1,'first'); 
     B(idxr,:)=[]; 
     B(:,idxc)=[]; 
     %store deletions 
     rdel(end+1)=idxr+sum(rdel<=idxr); 
     cdel(end+1)=idxc+sum(cdel<=idxc); 
    else 
     idxc=find(jh==max(jh),1,'first'); 
     B(:,idxc)=[]; 
     %store deletions 
     cdel(end+1)=idxc+sum(cdel<=idxc); 
    end 
end 
A(rdel,:)=0; 
A(:,cdel)=0; 
ind=find(A); 
+0

谢谢您的回复,并为失踪后我目前的进展很抱歉。我刚刚在原帖中加入了它。 我不知道如何检查结果是否由最大数量组成,但结果比我的结果多,而且你的代码没有嵌套循环,所以我认为你的代码比我的好。非常感谢你!! – Leba

+0

Hello Gelliant,我详细看了你的代码。对不起,我发现代码不会将矩阵修剪为矩形或超立方体形式。 – Leba

+0

确实。我的代码对于你的问题恐怕太简单了。可能的工作是种子和成长方法。您选择一个起点(必须是一个起点),并尝试在每个维度上交替增长以获得区域。当维度达到零时,您会停止增长。当算法停止时,您会记下大小并移至未在任何生长区域中的下一个种子。所有种子都经过测试后停止。请注意最高的区域。 – Gelliant