MATLAB:创建没有“侧NaN”列的较小矩阵

时间:2012-11-21 23:37:34

标签: matlab

我使用的是30 * 26000大小的矩阵,在开头和结尾都有NaN。 NaN也洒在每一排。我可以用线性插值填充NaN,但是会在每行的开头和结尾留下NaN。外推以在末端替换这些NaN对我的数据集来说并不理想。

我想修剪矩阵。以3乘6矩阵为例:

NaN NaN 1 2  3  NaN
NaN  1  2 3 NaN NaN
 1  NaN 2 3  4   5

切断最左侧和最右侧的列,使没有行开始以NaN结束。

1 2
2 3
2 3

所以我们留下了一个3乘2的矩阵。

我怎样才能在Matlab中做到这一点? (速度优化;我需要将其应用于百万大小的矩阵)

谢谢!

3 个答案:

答案 0 :(得分:7)

对于您的示例,您可以执行以下操作:

让你的矩阵用NaN和数值。

ind1 = sum(isnan(a),1); % count the NaN values along columns

s = find(ind1 == 0, 1, 'first'); % find the first column without any NaN

e = find(ind1 == 0, 1, 'last'); % find the last column without any NaN

所以现在只需将矩阵的这一部分从第s列保留到第e列:

b = a(:,s:e);

如果没有列没有NaN,则可能需要进一步检查。

答案 1 :(得分:2)

首先,argyris的矢量化解决方案能够很好地工作(+1)。我只发布了这个,因为你强调你想要一个速度优化的解决方案。好吧,argyris解决方案的缺点是在整个矩阵上执行sumisnan操作。如果你必须在任何一方找到第一个非NaN列,这将是最佳的。但是,如果你不这样做呢?一个基于循环的解决方案利用了您可能只需要进入几列的事实可能会做得更好(特别是考虑到JIT加速器在快速执行单个循环时获得的好处)。我已经整理了包括argyris和我的解决方案的速度测试:

%#Set up an example case using the matrix size you indicated in the question
T = 30;
N = 26000;
X = rand(T, N);
TrueL = 8;
TrueR = N - 8;
X(:, 1:TrueL) = NaN;
X(:, TrueR:end) = NaN;

%#argyris solution
tic
I1 = sum(isnan(X));
argL = find(I1 == 0, 1, 'first');
argR = find(I1 == 0, 1, 'last');
Soln1 = X(:, argL:argR);
toc

%#My loop based solution (faster if TrueL and TrueR are small)
tic
for n = 1:N
    if ~any(isnan(X(:, n)))
        break
    end
end
ColinL = n;
for n = N:-1:1
    if ~any(isnan(X(:, n)))
        break
    end
end
ColinR = n;
Soln2 = X(:, ColinL:ColinR);
toc

在上面的例子中,解决方案需要删除前8列和后8列。速度测试的结果?

Elapsed time is 0.002919 seconds. %#argyris solution
Elapsed time is 0.001007 seconds. %#My solution

基于循环的解决方案快了近3倍。好的,现在让我们需要将两侧的列数减少到100:

Elapsed time is 0.002769 seconds. %#argyris solution
Elapsed time is 0.001999 seconds. %#My solution

仍然领先。那两边1000列呢?

Elapsed time is 0.003597 seconds. %#argyris solution
Elapsed time is 0.003719 seconds. %#My solution

所以我们发现了我们的引爆点(至少在我的机器上 - 四核i7,Linux Mint v12,Matlab R2012b)。一旦我们需要在任何一侧进入大约1000列,我们最好使用矢量化解决方案。

注意事项的最后一点:如果例程发生在另一个(可能是不相关的)循环内,则应重新进行速度比较。这是因为我的解决方案现在将涉及双循环。即使循环不相关,JIT加速器也不如双循环。我在我的机器上进行了一些快速测试,我的解决方案仍然是小型TrueL和TrueR(即小于100),但优势并不像外部环路不存在时那么大。

无论如何,希望这证明对你或其他任何阅读过的人都有用。

干杯!

编辑:我做了一些速度测试,结合了angainor的非常简洁的单线程(+1)。当要删除的列数很小时,它的性能几乎与基于循环的解决方案一样好。令人惊讶的是,与argyris的解决方案不同,当要移除的色谱柱数量很大时,它并没有很好地扩展。这可能与我现在使用的计算机有关:工作Windows机器 - 我从未真正完全信任它:-)

答案 2 :(得分:2)

早先提出的两种解决方案都很棒,我发布这个单线条是为了完整性:

A(:,isfinite(sum(A)))

ans =

 1     2
 2     3
 2     3

通过首先计算行总和以及在调用isfinite之后,它避免两次通过矩阵条目(科林指出)。我还删除了find次调用 - 它们不是必需的,因为您可以使用逻辑索引。

我这里没有电脑,所以我省略了性能测试。