2017-07-31 79 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