找到最长的非纳米值序列但允许阈值

Emm*_*bbs 8 matlab

是否有可能找到一个向量的非纳米值,但也允许n个nans?例如,如果我有以下数据:

X = [18 3 nan nan 8 10 11 nan 9 14 6 1 4 23 24]; %// input array
thres = 1; % this is the number of nans to allow
Run Code Online (Sandbox Code Playgroud)

我想只保留最长的非nans值序列,但允许在数据中保留'n'个nans.所以,说我愿意保持1纳米,我会有一个输出

X_out = [8 10 11 nan 9 14 6 1 4 23 24]; %// output array
Run Code Online (Sandbox Code Playgroud)

那就是,开头的两个nans已被删除,因为它们超过了'thres'中的值,但是第三个nan本身就可以保存在数据中.我想开发一种方法,可以将thres定义为任何值.

我可以找到非纳米值

Y = ~isnan(X); %// convert to zeros and ones
Run Code Online (Sandbox Code Playgroud)

有任何想法吗?

m.s*_*.s. 8

为了找到含有最多最长的序列threshold时间NaN,我们必须找到一开始说序列(S)的结束.

要生成所有可能的起点,我们可以使用hankel:

H = hankel(X)

H =

    18     3   NaN   NaN     8    10    11   NaN     9    14     6     1     4    23    24
     3   NaN   NaN     8    10    11   NaN     9    14     6     1     4    23    24     0
   NaN   NaN     8    10    11   NaN     9    14     6     1     4    23    24     0     0
   NaN     8    10    11   NaN     9    14     6     1     4    23    24     0     0     0
     8    10    11   NaN     9    14     6     1     4    23    24     0     0     0     0
    10    11   NaN     9    14     6     1     4    23    24     0     0     0     0     0
    11   NaN     9    14     6     1     4    23    24     0     0     0     0     0     0
   NaN     9    14     6     1     4    23    24     0     0     0     0     0     0     0
     9    14     6     1     4    23    24     0     0     0     0     0     0     0     0
    14     6     1     4    23    24     0     0     0     0     0     0     0     0     0
     6     1     4    23    24     0     0     0     0     0     0     0     0     0     0
     1     4    23    24     0     0     0     0     0     0     0     0     0     0     0
     4    23    24     0     0     0     0     0     0     0     0     0     0     0     0
    23    24     0     0     0     0     0     0     0     0     0     0     0     0     0
    24     0     0     0     0     0     0     0     0     0     0     0     0     0     0 
Run Code Online (Sandbox Code Playgroud)

现在我们需要找到每一行中的最后一个有效元素.为此,我们可以使用cumsum:

C = cumsum(isnan(H),2)

C =

     0     0     1     2     2     2     2     3     3     3     3     3     3     3     3
     0     1     2     2     2     2     3     3     3     3     3     3     3     3     3
     1     2     2     2     2     3     3     3     3     3     3     3     3     3     3
     1     1     1     1     2     2     2     2     2     2     2     2     2     2     2
     0     0     0     1     1     1     1     1     1     1     1     1     1     1     1
     0     0     1     1     1     1     1     1     1     1     1     1     1     1     1
     0     1     1     1     1     1     1     1     1     1     1     1     1     1     1
     1     1     1     1     1     1     1     1     1     1     1     1     1     1     1
     0     0     0     0     0     0     0     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0     0     0     0     0     0     0     0
Run Code Online (Sandbox Code Playgroud)

每行的结束点是一个,其中相应的元素C最多threshold:

threshold = 1;

T = C<=threshold

T =

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

最后一个有效元素使用:

[~,idx]=sort(T,2);
lastone=idx(:,end)

lastone =

 3     2     1     4    15    15    15    15    15    15    15    15    15    15    15
Run Code Online (Sandbox Code Playgroud)

我们必须确保每行的实际长度得到遵守:

lengths = length(X):-1:1;
real_length = min(lastone,lengths);
[max_length,max_idx] = max(real_length)


max_length =

     11


max_idx =

     5
Run Code Online (Sandbox Code Playgroud)

如果有更多相等的最大长度的序列,我们只需取第一个并显示它:

selected_max_idx = max_idx(1);
H(selected_max_idx, 1:max_length)


ans =

 8    10    11   NaN     9    14     6     1     4    23    24
Run Code Online (Sandbox Code Playgroud)

完整的脚本

X = [18 3 nan nan 8 10 11 nan 9 14 6 1 4 23 24];

H = hankel(X);
C = cumsum(isnan(H),2);

threshold = 1;

T = C<=threshold;
[~,idx]=sort(T,2);
lastone=idx(:,end)';

lengths = length(X):-1:1;
real_length = min(lastone,lengths);
[max_length,max_idx] = max(real_length);

selected_max_idx = max_idx(1);
H(selected_max_idx, 1:max_length)
Run Code Online (Sandbox Code Playgroud)


Lui*_*ndo 5

方法1:卷积

一种可能的方法是Y = double(~isnan(X));用一个窗口进行卷积n,其中n减少直到找到可接受的子序列."可接受"意味着子序列至少包含n-thres一个,即卷积至少给出n-thres.

Y = double(~isnan(X));
for n = numel(Y):-1:1 %// try all possible sequence lengths
    w = find(conv(Y,ones(1,n),'valid')>=n-thres); %// is there any acceptable subsequence?
    if ~isempty(w)
        break
    end
end
result = X(w:w+n-1);
Run Code Online (Sandbox Code Playgroud)

Aproach 2:累计金额

卷积Y用的窗口n的人(如在方法1)等同于计算的累加值Y,然后采取与差异n间距.这在操作次数方面更有效.

Y = double(~isnan(X));
Z = cumsum(Y);
for n = numel(Y):-1:1
    w = find([Z(n) Z(n+1:end)-Z(1:end-n)]>=n-thres);
    if ~isempty(w)
        break
    end
end
result = X(w:w+n-1);
Run Code Online (Sandbox Code Playgroud)

方法3:2D卷积

这基本上一次计算方法1中循环的所有迭代.

Y = double(~isnan(X));
z = conv2(Y, tril(ones(numel(Y))));
[nn, ww] = find(bsxfun(@ge, z, (1:numel(Y)).'-thres)); %'
[n, ind] = max(nn);
w = ww(ind)-n+1;
result = X(w:w+n-1);
Run Code Online (Sandbox Code Playgroud)