matlab 求包含nan个值的矩阵的子矩阵,使得子矩阵覆盖最大数量的已知值

puruo6ea  于 2022-11-30  发布在  Matlab
关注(0)|答案(1)|浏览(138)

给定任意维数的矩阵NaN,其中在某个反对角下所有的值都是未知的,我想提取没有NaN值的子矩阵,这些子矩阵尽可能大,使得原始矩阵中的元素尽可能多地包含在子矩阵中。每个子矩阵必须至少为R a x x R。其中R可以由用户指定。子矩阵可以相互重叠。我可以找到所有元素都是NaN的反对角,但我真的不知道如何将矩阵的非NaN部分划分为子矩阵,以尽可能多地覆盖已知值。
下图说明了如何将矩阵的数值部分划分为R = 3的子矩阵:Possible submatrix division
下面的代码:

mask = ~isnan(A);
nrKnownElsRow = sum(mask,2);
dims = [[1:length(nrKnownElsRow)]' nrKnownElsRow];
dims(dims(:,2)<R,:) = [];
dims(dims(:,1)<R,:) = [];
idx = find(dims(:,2) == max(dims(:,2)));
dims(idx(1:end-1),:) = [];
dims = [dims(:,1) zeros(length(dims),1) dims(:,2)];

for k = 1:length(dims)-1
    if dims(k,3) - dims(k+1,3) >= R
        dims(k,2) = dims(k+1,3) + 1;
    else
        dims(k,2) = dims(k,3) - R + 1;
    end
end
dims(end,2) = 1;

变量dims在对应子矩阵的每一行中包含子Tensor所到达的行,然后是组成子矩阵的外部列。这使用了矩阵中尽可能多的信息,但子矩阵不是尽可能大。

p5fdfcr1

p5fdfcr11#

下面的解决方案并不完美,但它可能会帮助您入门。
此脚本捕获所有边为1或两边均大于r(定义为R的阈值)的子矩阵。

close all;clear all;clc

N1=10;N2=10  % A size
% avoid N1=1 N2=1

r=3; % threshold

生成A

A=reshape(randi([1 10],1,N1*N2),N1,N2); % generating A
n0=randi([1 5],1,1)            % define amount NaN to scatter in A
% n0=1 % test
n1=randi([2 N1-1],1,n0);
n2=randi([2 N2-1],1,n0);
A(sub2ind([N1 N2],n1,n2))=NaN

查找NaNs坐标

A2=isnan(A);
[nan_row,nan_col]=find(A2>0)
nan_row=sort(nan_row);nan_col=sort(nan_col);

% calculate coordinates combinations, no repetition
L1=[1 1;nan_row,nan_col;N1 N2];
L2x=nchoosek(L1(:,2),2) % 1D coord combinations
L2y=nchoosek(L1(:,1),2)

现在,L2xL2y包含所有单坐标组合
L2xL2y组合成单个变量L3

[cx,cy]=meshgrid([1:1:size(L2x,1)],[1:1:size(L2y,1)])

L3=[L2x(cx(:),:) L2y(cy(:),:)]      

trim borders of all submatrixes
for k1=1:1:size(L3,1)                  
    if L3(k1,1)==1 && L3(k1,2)<N1
        L3(k1,2)=L3(k1,2)-1;
    end
    if L3(k1,1)>1 && L3(k1,2)==N1
        L3(k1,1)=L3(k1,1)+1;
    end
    if L3(k1,1)>1 && L3(k1,2)<N1
        L3(k1,1)=L3(k1,1)-1;
        L3(k1,2)=L3(k1,2)+1;
    end
end
for k1=1:1:size(L3,1)                 
    if L3(k1,3)==1 && L3(k1,4)<N2
        L3(k1,4)=L3(k1,4)-1;
    end
    if L3(k1,3)>1 && L3(k1,4)==N2
        L3(k1,3)=L3(k1,3)+1;
    end
    if L3(k1,3)>1 && L3(k1,4)<N2
        L3(k1,3)=L3(k1,3)-1;
        L3(k1,4)=L3(k1,4)+1;
    end
end
% L3

移除任何包含NaN的子矩阵

cnan=zeros(1,size(L3,1))
for k3=1:1:numel(cnan)
    A4=A(L3(k3,3):L3(k3,4),L3(k3,1):L3(k3,2))
    if nonzeros(isnan(A4));
        cnan(k3)=1   % contains NaN(s)
    end
end
L3(cnan>0,:)=[]

计算所有子矩阵组合、对子矩阵,无重复

nL3=nchoosek(size(L3,1),2)  % how many pairs
cnL3=nchoosek([1:size(L3,1)],2)

在每条cnL3线上附加一个标记,以表明是a1(a2),还是a2(a1),还是a1==a2。
cnL3[ ... A51_contains_A52 A52_contains_A51]

cnL3=[cnL3 zeros(size(cnL3,1),2)]

谁包含谁

for k3=1:1:nL3
    d1=L3(cnL3(k3,1),:)
    d2=L3(cnL3(k3,2),:)
    
    if (d1(1)<d2(1) && d1(2)>d2(2) && d1(3)<d2(3) && d1(4)>d2(4)) || ...  % A51 contains A52
       (d1(1)<=d2(1) && d1(2)>=d2(2) && d1(3)<=d2(3) && d1(4)>d2(4)) || ...  % 3 side    
       (d1(1)<=d2(1) && d1(2)>=d2(2) && d1(3)<d2(3) && d1(4)>=d2(4)) || ...
       (d1(1)<=d2(1) && d1(2)>d2(2) && d1(3)<=d2(3) && d1(4)>=d2(4)) || ...
       (d1(1)<d2(1) && d1(2)>=d2(2) && d1(3)<=d2(3) && d1(4)>=d2(4)) || ...
       (d1(1)<=d2(1) && d1(2)>=d2(2) && d1(3)<d2(3) && d1(4)>d2(4)) || ...    % 2 side
       (d1(1)<=d2(1) && d1(2)>d2(2) && d1(3)<d2(3) && d1(4)>=d2(4)) || ...
       (d1(1)<d2(1) && d1(2)>d2(2) && d1(3)<=d2(3) && d1(4)>=d2(4)) || ...
       (d1(1)<d2(1) && d1(2)>=d2(2) && d1(3)<=d2(3) && d1(4)>d2(4)) || ...
       (d1(1)<=d2(1) && d1(2)>d2(2) && d1(3)<d2(3) && d1(4)>d2(4)) || ...   % 1 side
       (d1(1)<d2(1) && d1(2)>d2(2) && d1(3)<d2(3) && d1(4)>=d2(4)) || ...
       (d1(1)<d2(1) && d1(2)>d2(2) && d1(3)<=d2(3) && d1(4)>d2(4)) || ...
       (d1(1)<d2(1) && d1(2)>=d2(2) && d1(3)<d2(3) && d1(4)>d2(4))
          cnL3(k3,3)=1; 
    end
  
    if (d2(1)<d2(1) && d2(2)>d2(2) && d2(3)<d2(3) && d2(4)>d2(4)) || ...   % A52 contains A51
       (d2(1)<=d2(1) && d2(2)>=d2(2) && d2(3)<=d2(3) && d2(4)>d2(4)) || ...    
       (d2(1)<=d2(1) && d2(2)>=d2(2) && d2(3)<d2(3) && d2(4)>=d2(4)) || ...
       (d2(1)<=d2(1) && d2(2)>d2(2) && d2(3)<=d2(3) && d2(4)>=d2(4)) || ...
       (d2(1)<d2(1) && d2(2)>=d2(2) && d2(3)<=d2(3) && d2(4)>=d2(4)) || ...
       (d2(1)<=d2(1) && d2(2)>=d2(2) && d2(3)<d2(3) && d2(4)>d2(4)) || ...    
       (d2(1)<=d2(1) && d2(2)>d2(2) && d2(3)<d2(3) && d2(4)>=d2(4)) || ...
       (d2(1)<d2(1) && d2(2)>d2(2) && d2(3)<=d2(3) && d2(4)>=d2(4)) || ...
       (d2(1)<d2(1) && d2(2)>=d2(2) && d2(3)<=d2(3) && d2(4)>d2(4)) || ...
       (d2(1)<=d2(1) && d2(2)>d2(2) && d2(3)<d2(3) && d2(4)>d2(4)) || ...   
       (d2(1)<d2(1) && d2(2)>d2(2) && d2(3)<d2(3) && d2(4)>=d2(4)) || ...
       (d2(1)<d2(1) && d2(2)>d2(2) && d2(3)<=d2(3) && d2(4)>d2(4)) || ...
       (d2(1)<d2(1) && d2(2)>=d2(2) && d2(3)<d2(3) && d2(4)>d2(4))
          cnL3(k3,4)=1; 
    end
    
    % A51=A(d1(3):d1(4),d1(1):d1(2)) % checks
    % A52=A(d2(3):d2(4),d2(1):d2(2))
  
end

含子矩阵偶

[drow,dcol]=find(cnL3(:,3)==1 | cnL3(:,4)==1)

从子矩阵列表L3中删除包含的子矩阵

cnt=[]
for k3=1:1:numel(drow)
    L5=cnL3(drow(k3),:);
    if L5(3)==1 cnt=[cnt L5(2)]; end
    if L5(4)==1 cnt=[cnt L5(1)]; end
end
cnt=unique(cnt)
L4=L3
L4(cnt,:)=[]
L4

X:包含所有符合子矩阵的单元格

X={}    
for k1=1:1:size(L4,1)
    X=[X A(L4(k1,3):L4(k1,4),L4(k1,1):L4(k1,2))];
end
X

阅读单元格X的1个元素

X{1}

如何做一个细胞全力

X{:}

只需键入X,MATLAB就会返回单元格X内所有大小的元素

just example 
X 
=
1×4 cell array
Columns 1 through 2
{10×5 double}    {7×10 double}
Columns 3 through 4
{2×10 double}    {10×4 double}

现在是您要求的阈值r

XR=X;
L5=diff(L4,1,2)+1  % calculating sizes
L5(:,[2:2:end])=[]
[rrow,rcol]=find(L5<r)
XR(rrow)=[]
XR{:}

这对我查过的几个案子都有效。
注:我生成的测试矩阵沿着没有NaN。
Stijn,如果这个解决方案有帮助的话,请你考虑一下,把它作为有效的答案?
感谢阅读

相关问题