强制"独特"将NaNs视为模糊不清

cra*_*gim 5 matlab

我有一个代表分子状态的长数字矩阵.子集可能如下所示:

 states = [...
  1     1     1     1
  1     1     1     1
  1     0     1     1
NaN     0   NaN   NaN
  1     0     1     0
  1     0     1     1
NaN   NaN   NaN   NaN
  1     0     1     1
NaN   NaN   NaN   NaN
  1     1     0     0
 ];
Run Code Online (Sandbox Code Playgroud)

其中NaN值是表示未知的状态.实际上,此列表可能包含数十万个值.如果我使用该unique命令获取唯一状态,结果看起来像

K>>unique(states,'rows')

ans = 

     1     0     1     0
     1     0     1     1
     1     1     0     0
     1     1     1     1
   NaN     0   NaN   NaN
   NaN   NaN   NaN   NaN
   NaN   NaN   NaN   NaN
Run Code Online (Sandbox Code Playgroud)

因为"独特的将NaN值视为独特".

如何按下此输出以使NaN值不明显?那[NaN NaN NaN NaN]是不同的[NaN 0 NaN NaN]但是[NaN NaN NaN NaN] == [NaN NaN NaN NaN]

Div*_*kar 2

代码

%// Get unique rows with in-built "unique" that considers NaN as distinct
unq1 = unique(states,'rows');

%// Detect nans
unq1_nans = isnan(unq1);

%// Find nan equalities across rows
unq1_nans_roweq = bsxfun(@plus,unq1_nans,permute(unq1_nans,[3 2 1]))==2;

%// Find non-nan equalities across rows
unq1_nonans_roweq = bsxfun(@eq,unq1,permute(unq1,[3 2 1]));

%// Find "universal" (nan or non-nan) equalities across rows
unq1_univ_roweq = unq1_nans_roweq | unq1_nonans_roweq;

%// Remove non-unique rows except the first non-unique match as with 
%// the default functionality of MATLAB's in-built unique function
out = unq1(~any(triu(squeeze(sum(unq1_univ_roweq,2)==size(states,2)),1),1),:);
Run Code Online (Sandbox Code Playgroud)

例子#1

输入 -

states =
    3.0000    1.0000    7.0000    8.0000
    8.0000         0    1.0000    6.0000
       Inf         0       NaN       NaN
    5.0000         0    1.0000         0
       Inf         0       NaN       NaN
    7.0000         0    5.0000    1.0000
       NaN       NaN   11.2000       Inf
       NaN       NaN   15.0000       NaN
       NaN       NaN   11.2000       Inf
Run Code Online (Sandbox Code Playgroud)

使用 MATLAB 内置unique+ 'rows'-的中间结果

unq1 =
    3.0000    1.0000    7.0000    8.0000
    5.0000         0    1.0000         0
    7.0000         0    5.0000    1.0000
    8.0000         0    1.0000    6.0000
       Inf         0       NaN       NaN
       Inf         0       NaN       NaN
       NaN       NaN   11.2000       Inf
       NaN       NaN   11.2000       Inf
       NaN       NaN   15.0000       NaN
Run Code Online (Sandbox Code Playgroud)

请注意,具有相同值的两行 -[Inf 0 NaN NaN]仍然显示,同样,我们还有另一个相同的对 - [NaN NaN 11.2000 Inf]。我们需要为这两对中的每一对保留一个唯一的行。让我们看看我们的代码如何执行 -

out =
    3.0000    1.0000    7.0000    8.0000
    5.0000         0    1.0000         0
    7.0000         0    5.0000    1.0000
    8.0000         0    1.0000    6.0000
       Inf         0       NaN       NaN
       NaN       NaN   11.2000       Inf
       NaN       NaN   15.0000       NaN
Run Code Online (Sandbox Code Playgroud)

效果还不错!

例子#2

对于最终测试,让我们测试一下输入数组中也有大数字的情况,如下所示 -

states =
            3            1            7            8
            8            0            1            6
          Inf            0          NaN          NaN
            5            0            1            0
          Inf            0          NaN          NaN
            7            0            5            1
          NaN          NaN       1e+100          Inf
          NaN          NaN           15          NaN
          NaN          NaN       1e+100          Inf
Run Code Online (Sandbox Code Playgroud)

unique带+的中间结果'rows'将是 -

unq1 =
            3            1            7            8
            5            0            1            0
            7            0            5            1
            8            0            1            6
          Inf            0          NaN          NaN
          Inf            0          NaN          NaN
          NaN          NaN           15          NaN
          NaN          NaN       1e+100          Inf
          NaN          NaN       1e+100          Inf
Run Code Online (Sandbox Code Playgroud)

因此,我们的代码必须删除最后两行之一。

out =
            3            1            7            8
            5            0            1            0
            7            0            5            1
            8            0            1            6
          Inf            0          NaN          NaN
          NaN          NaN           15          NaN
          NaN          NaN       1e+100          Inf
Run Code Online (Sandbox Code Playgroud)

确实如此!