在每列的矩阵中查找最后两个非NaN唯一观测值

时间:2018-03-16 15:13:13

标签: matlab find unique

我有一个矩阵A,我希望每列找到最后两个非NaN值。

例如,生成以下矩阵:

A = [NaN, 3, NaN; 5  5  5; NaN  1  9;  4  1   4;  NaN  6   NaN;  6   2   9]

我想得到以下结果:

B =

     4     6     4
     6     2     9

如何在没有for循环的情况下以最有效的方式执行此操作?

我尝试了以下内容:[row,col,v] = find(A,3,'last'),但这会返回一些我不理解的内容:

row =

     5
     6


col =

     3
     3


v =

   NaN
     9

2 个答案:

答案 0 :(得分:3)

find的第三个参数实际上找到了非零的实际位置。它以列为单位进行搜索,并返回最后三个非零值及其实际值的行和列位置。 NaN在技术上是非零的,这就是它返回给你的原因。

首先,使用NaN查找矩阵中不是find的所有位置:

[I,J] = find(~isnan(A));

现在将返回非NaN值的行和列位置。我们现在得到:

>> [I,J]

ans =

     2     1
     4     1
     6     1
     1     2
     2     2
     3     2
     4     2
     5     2
     6     2
     2     3
     3     3
     4     3
     6     3

我们可以看到一个漂亮的图案形成。左列显示了不是NaN的所有行位置,右列显示了哪个列。

接下来我们可以做的是第二列,找到我们从一列转换到另一列的点。这将为我们提供每列不是NaN的最后一个元素的位置。然后我们可以将这些索引减去1,以便给出第二个不是NaN的最后一个元素的位置。我们可以使用diff函数帮助我们这样做,并检查距离是否为非零。请注意,这将减少输出的大小1,因为我们计算成对距离,但只是在末尾填充1,因为这表示最后一列的结束,这是我们想要找到最后两个元素的位置专栏:

>> d = [diff(J) ~= 0; 1];
>> [J d]

ans =

     1     0
     1     0
     1     1
     2     0
     2     0
     2     0
     2     0
     2     0
     2     1
     3     0
     3     0
     3     0
     3     1

现在让我们取diff的输出并将所有内容向上移动1:

d(1:end-1) = d(1:end-1) | d(2:end);

这将允许我们标记要捕获的每列的倒数第二个元素:

>> [I J d]

ans =

     2     1     0
     4     1     1
     6     1     1
     1     2     0
     2     2     0
     3     2     0
     4     2     0
     5     2     1
     6     2     1
     2     3     0
     3     3     0
     4     3     1
     6     3     1

最后但并非最不重要的是,我们现在对上面矩阵的前两列进行采样,其中第三列非零,将这些列转换为线性索引并对矩阵进行采样。我们将使用reshapesub2ind的组合:

loc = d ~= 0;
out = reshape(A(sub2ind(size(A), I(loc), J(loc))), 2, size(A,2));

因此:

>> out

out =

     4     6     4
     6     2     9

最终的代码是:

[I,J] = find(~isnan(A));
d = [diff(J) ~= 0; 1];
d(1:end-1) = d(1:end-1) | d(2:end);
loc = d ~= 0;
out = reshape(A(sub2ind(size(A), I(loc), J(loc))), 2, size(A,2));

警告

这假设每列至少有两个元素不是NaN

答案 1 :(得分:2)

这是:

A = [NaN, 3, NaN; 5  5  5; NaN  1  9;  4  1   4;  NaN  6   NaN;  6   2   9]
N=2; %last 2
IsOK=~isnan(A);
[~,I]=sort(IsOK);
Iok=I(end-N+1:end,:); %get last N
LinearIndxs=sub2ind(size(A), Iok, repmat(1:size(A,2),N,1));
Result=A(LinearIndxs)