我有三个相同大小的matlab矩阵A,B和C:
A = [1:3; 4:6; 7:9];
B = [2 NaN 5; NaN NaN 7; 0 1 NaN];
C = [3 NaN 2; 1 NaN NaN; 1 NaN 5];
%>> A = %>>B = %>>C =
% 1 2 3 % 2 NaN 5 % 3 NaN 2
% 4 5 6 % NaN NaN 7 % 1 NaN NaN
% 7 8 9 % 0 1 NaN % 1 NaN 5
我希望这三个矩阵只保留3个矩阵中每个矩阵在该特定位置都没有NaN的值。也就是说,我想获得以下内容:
%>> A = %>>B = %>>C =
% 1 NaN 3 % 2 NaN 5 % 3 NaN 2
% NaN NaN NaN % NaN NaN NaN % NaN NaN NaN
% 7 NaN NaN % 0 NaN NaN % 1 NaN NaN
在我的尝试中,我沿着尺寸为3x3x3的新矩阵ABC的第三维堆叠三个矩阵,然后我使用for循环来确保所有三个矩阵都没有NaN在那个特定的位置。
ABC(:,:,1)=A; ABC(:,:,2)=B; ABC(:,:,3)=C;
for i=1:size(A,1)
for j=1:size(A,2)
count = squeeze(ABC(i,j,:));
if sum(~isnan(count))<size(ABC,3)
A(i,j)=NaN;
B(i,j)=NaN;
C(i,j)=NaN;
end
end
end
此代码工作正常。但是,由于我有超过30个更大尺寸的矩阵,我想知道是否有一个更优雅的解决方案来解决这个问题。
感谢您的帮助。
答案 0 :(得分:2)
让我们做一下花哨的索引!
首先,解决方案:
indnan=sum(isnan(cat(3,A,B,C)),3)>0;
A(indnan)=NaN;
B(indnan)=NaN;
C(indnan)=NaN;
此代码的作用基本上是创建一个3D矩阵,并计算每个NaN
数组中有多少(i,j,:)
。然后,如果有超过0
(即其中任何一个是NaN
),它将获得它的逻辑索引。最后,我们填写NaN
的所有人,只留下非NaN
。
答案 1 :(得分:1)
Ander’s answer很好,但对于非常大的矩阵,创建3D矩阵可能会很昂贵。
首先,我建议将矩阵放入单元格数组中。这使得以编程方式管理许多数组变得更加容易。也就是说,而不是A
,B
等,与C{1}
,C{2}
等合作:
C = {A,B,C};
进行此更改基本上只需零成本。
现在,找到其中一个矩阵为NaN的所有元素:
M = isnan(C{1});
for ii=2:numel(C)
M = M | isnan(C{ii});
end
然后,类似的循环将相应的元素设置为NaN:
for ii=1:numel(C)
C{ii}(M) = NaN,
end
后一个循环可以被cellfun
调用替换,但我喜欢显式循环。
编辑:以下是一些时间安排。这是现代MATLAB中循环比等效矢量化代码更快的另一个例子。回到过去,循环代码的速度会慢100倍。
这是测试代码:
function so(sz) % input argument is the size of the arrays
C3 = cell(1,3);
for ii=1:numel(C3)
C3{ii} = create(sz,0.05);
end
C20 = cell(1,20);
for ii=1:numel(C20)
C20{ii} = create(sz,0.01);
end
if(~isequal(method1(C3),method2(C3))), error('not equal!'), end
if(~isequal(method1(C20),method2(C20))), error('not equal!'), end
fprintf('method 1, 3 arrays: %f s\n',timeit(@()method1(C3)))
fprintf('method 2, 3 arrays: %f s\n',timeit(@()method2(C3)))
fprintf('method 1, 20 arrays: %f s\n',timeit(@()method1(C20)))
fprintf('method 2, 20 arrays: %f s\n',timeit(@()method2(C20)))
% method 1 is the vectorized code from Ander:
function mask = method1(C)
mask = sum(isnan(cat(3,C{:})),3)>0;
% method 2 is the loop code from this answer:
function mask = method2(C)
mask = isnan(C{1});
for ii=2:numel(C)
mask = mask | isnan(C{ii});
end
function mat = create(sz,p)
mat = rand(sz);
mat(mat<p) = nan;
这些是我的机器上的结果(使用R2017a):
>> so(500)
method 1, 3 arrays: 0.003215 s
method 2, 3 arrays: 0.000386 s
method 1, 20 arrays: 0.016503 s
method 2, 20 arrays: 0.001257 s
循环快10倍!对于小型阵列,我看到的差别要小得多,但循环代码仍然快几倍,即使对于5x5阵列也是如此。