我有一个代表分子状态的长数字矩阵。子集可能如下所示:
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
];
其中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
因为" unique将NaN值视为不同的"。
如何按下此输出,使NaN值不明显?因此[NaN NaN NaN NaN]
与[NaN 0 NaN NaN]
不同,但[NaN NaN NaN NaN] == [NaN NaN NaN NaN]
?
答案 0 :(得分:2)
这是一个部分(并且不令人满意)的答案,适用于这个特定的实例,但不是一般的:
states(isnan(states)) = inf;
uniqueStates = unique(states,'rows');
uniqueStates(~isfinite(uniqueStates)) = nan;
显然MATLAB不会将Inf
值视为不同。我不打算在我的应用程序中包含任何Inf
值,但我当然可以想象一个同时包含Inf
和NaN
值的情况,在这种情况下,这会使它们混乱
实际答案:
所以@Louis Mendo删除了他的评论,这使我得出了最终答案,但这似乎很有力:
function C = nanUnique(varargin)
A = varargin{1};
dummyVal = ceil(max(A(isfinite(A(:))))) + 1;
A(isnan(A)) = dummyVal;
C = unique(A,varargin{2:end});
C(C==dummyVal) = nan;
简而言之,找到最大值(即无穷大)。向上舍入的值+ 1是一个整数(没有浮点错误)并保证是唯一的。将所有NaN
替换为虚拟值,运行unique
,然后将NaN
放回原来的位置。
答案 1 :(得分: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),:);
示例#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
使用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
请注意,两个具有相同值的行 - [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
没关系!
示例#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
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
因此,我们的代码必须删除最后两行中的一行。
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
确实如此!
答案 2 :(得分:1)
建议的其他解决方案更简单。
但是你可以考虑继承double
类型。
您需要通过创建自己的eq()
方法覆盖==
运算符,该方法应使用isequaln()
(NaN值被视为相等)。
无论如何,需要考虑的事情。