我的数据集不完整,
N = [NaN 1 2 3 NaN 5 6 NaN NaN 7 8 10 12 20 NaN NaN NaN NaN NaN]'
我希望识别一组Nans,也就是说,如果它们的后续数量超过2.我该怎么做?
答案 0 :(得分:5)
你可以这样做:
aux = diff([0; isnan(N); 0]);
clusters = [find(aux == 1) find(aux == -1) - 1];
然后,群集将是Nx2矩阵,其中N是NaN群集的数量(所有群集),每行都为您提供群集的起始和结束索引。
在这个例子中,那将是:
clusters =
1 1
5 5
8 9
15 19
这意味着你有4个NaN集群,集群1从索引1到索引1,集群2从5到5,集群3从8到9,集群4从15到19。
如果您只想要具有至少K
个NaN的群集,您可以这样做(例如,K = 2):
K = 2;
clusters(clusters(:,2) - clusters(:,1) + 1 >= K, :)
那会给你这个:
ans =
8 9
15 19
即,簇8-9和15-19具有2个或更多个NaN。
<强>解释强>
isnan(N)
为您提供一个包含NaN为1的逻辑向量:
N --------> NaN 1 2 3 NaN 5 6 NaN NaN 7 8 10 12 20 NaN NaN NaN NaN NaN
isnan(N) -> 1 0 0 0 1 0 0 1 1 0 0 0 0 0 1 1 1 1 1
我们想知道每个序列的起始位置,因此我们使用diff
计算每个值减去前一个值,然后给出:
aux = diff(isnan(N));
N ----> NaN 1 2 3 NaN 5 6 NaN NaN 7 8 10 12 20 NaN NaN NaN NaN NaN
aux --> -1 0 0 1 -1 0 1 0 -1 0 0 0 0 1 0 0 0 0
1
表示组开始,-1
表示组结束。但它错过了第一组开始和最后一组结束,因为第一个1
元素不存在(它没有前一个N
,因为它是第一个)和最后一个-1
{1}}也不存在(因为1
上的最后N
之后没有任何内容。一个常见的解决方法是在数组之前和之后添加零,这样就可以得到:
aux = diff([0; isnan(N); 0]);
N ----> NaN 1 2 3 NaN 5 6 NaN NaN 7 8 10 12 20 NaN NaN NaN NaN NaN
aux --> 1 -1 0 0 1 -1 0 1 0 -1 0 0 0 0 1 0 0 0 0 -1
注意两件事:
i
的差异为1
,则N(i)
是NaN块的开头。i
的差异为-1
,则 N(i - 1)
是NaN块的结尾。要获得开始和结束,我们使用find
来获取aux == 1和aux == -1的索引。因此,我们拨打find
两次,并使用[
和]
连接两个来电:
aux = diff([0; isnan(N); 0]);
clusters = [find(aux == 1) find(aux == -1) - 1];
最后一步是找到具有K个或更多元素的集群。为此,我们首先采用聚类矩阵并从第一列中减去第一列,并添加1
,如下所示:
clusters(:,2) - clusters(:,1) + 1
ans =
1
1
2
5
这意味着簇1和2具有1个NaN,簇3具有3个NaN,簇4具有5个NaN。如果我们问哪个值大于或等于K,我们得到这个:
clusters(:,2) - clusters(:,1) + 1 >= K
ans =
0
0
1
1
它是一个逻辑阵列。我们可以使用它来仅索引集群矩阵的1
(true)行,如下所示:
clusters(clusters(:,2) - clusters(:,1) + 1 >= K, :)
ans =
8 9
15 19
这就像问:给我们只给出行与这个逻辑向量上的行匹配的簇,并给我们所有列(用:
表示)。
答案 1 :(得分:2)
这是一个模块化解决方案:
% the number of NaN you consider as a cluster
num = 3;
% moving average filter
Z = filter(ones(num,1),1,isnan(N));
x = arrayfun(@(x) find(Z == num) - num + x, 1:num,'uni',0)
y = unique(cell2mat(x))
(更新:以下更快的版本)
给出了num = 1
:
y = 1 5 8 9 15 16 17 18 19
代表num = 2
:
y = 8 9 15 16 17 18 19
代表num = 3
,num = 4
和num = 5
:
y = 15 16 17 18 19
最后是num = 6
...以及更多
y = Empty matrix: 1-by-0
<强>解释强>
isnan(N)
返回一个逻辑数组,其中的位置为NaN
。
Z = filter(ones(num,1),1,isnan(N));
是移动平均滤镜的实现,滤镜窗口为ones(num,1) = [1 1 1]
(num = 3
)。因此,当行中有3个num = 3
时,大小为3的过滤器会滑动数组并达到值NaN
。
所以它的basicall看起来像:
%// N isnan(N) Z
NaN 1 1
1 0 1
2 0 1
3 0 0
NaN 1 1
5 0 1
6 0 1
NaN 1 1
NaN 1 2
7 0 2
8 0 1
10 0 0
12 0 0
20 0 0
NaN 1 1
NaN 1 2
NaN 1 3
NaN 1 3
NaN 1 3
现在很容易找到所有 3 :find(Z == num)
的元素 - 但您还需要之前的所有 2 :find(Z == num) - num + 2
和以前所有 1 :find(Z == num) - num + 1
。而不是使用循环arrayfun,这基本上是相同的。结果你会得到一个包含很多索引的矩阵,其中很多都是多余的,但你只需要unique
个。我希望现在一切都清楚了。
实际上,将find
从arrayfun中取出会快得多,然后甚至可以用bsxfun
代替,你可以摆脱cell2mat
,这会导致以下形式:
<强>更快强>
Z = find( filter(ones(num,1),1,isnan(N)) == num ) - num;
y = unique( bsxfun(@plus, Z,1:num) );
或更快的强制性花哨的单行:
y = unique(bsxfun(@plus,find(filter(ones(num,1),1,isnan(N))==num)-num,1:num));
答案 2 :(得分:1)
STRFIND方法
<强>予。 Fancy One Liner:
%%// Given input N
N = [NaN 1 2 3 NaN 5 6 NaN NaN 7 8 10 12 20 NaN NaN NaN NaN NaN]
out = [strfind(num2str(isnan([ 0 N 0]),'%1d'),'011');strfind(num2str(isnan([ 0 N 0]),'%1d'),'110')]'
<强>输出强>
out =
8 9
15 19
<强> II。详细解释:
基本上你正在尝试进行滑动窗口检查,在使用双数组时没有直接的方法,但在转换为字符串后,可以使用strfind
。这个技巧在这里使用。
我建议按照代码中使用的注释和输出数字来理解它。请注意,对于这种特殊情况,群集意味着一组两个或多个连续的NaN
<强>代码强>
%%// Given input N
N = [NaN 1 2 3 NaN 5 6 NaN NaN 7 8 10 12 20 NaN NaN NaN NaN NaN]
%%// Set the locations where NaNs are present and then
%%// append at the start and end with zeros
N2 = isnan([ 0 N 0])
%%// Find the start indices of all NaN clusters
start_ind = strfind(num2str(N2,'%1d'),'011')
%%// Find the stop indices of all NaN clusters
stop_ind = [strfind(num2str(N2,'%1d'),'110')]
%%// Put start and stop indices into a Mx2 matrix
out = [start_ind' stop_ind']
<强>输出强>
N =
NaN 1 2 3 NaN 5 6 NaN NaN 7 8 10 12 20 NaN NaN NaN NaN NaN
N2 =
0 1 0 0 0 1 0 0 1 1 0 0 0 0 0 1 1 1 1 1 0
start_ind =
8 15
stop_ind =
9 19
out =
8 9
15 19
答案 3 :(得分:0)
这使用diff
,Rafael Monteiro's answer,但似乎更简单:
ind = diff([0; isnan(N(:))]);
result = find(ind(1:end-1)==1 & ind(2:end)==0);
在您的示例中,这会给出[8 15]
。
工作原理:ind
获取值:
1
其中一个(一个或多个)NaN
值的运行开始; 0
其中NaN
和数字相对于之前的值没有变化; -1
开始运行(一个或多个)数值。第二行选择NaN
开始运行的位置,以便下一个位置也是NaN
。因此,它根据需要为每次运行提供多个NaN
。