我有一个矩阵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
答案 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
最后但并非最不重要的是,我们现在对上面矩阵的前两列进行采样,其中第三列非零,将这些列转换为线性索引并对矩阵进行采样。我们将使用reshape
和sub2ind
的组合:
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)