MATLAB:用NaN替换每列的前导零

And*_*ndi 1 matlab for-loop vectorization

我有一个名为的3D矩阵mat.每列可以包含或不包含可变数量的前导零.我需要用NaN替换它们.重要的是要认识到在第一个非零元素出现后,任何列中可能会跟随更多的零.也就是说,只需在矩阵中索引全零并用NaN替换它们就不会产生正确的结果.

我确实有一个有效的解决方案.但是,它包含两个for循环.我想知道是否有可能进行矢量化并摆脱循环.实际上,mat可能非常大,比如10000x15x10000.因此,我对执行速度非常敏感.

这是我的玩具示例:

% Create test matrix
mat = randi(100,20,5,2);
mat(1:5,1,1) = 0;
mat(1:7,2,1) = 0;
mat(1:3,4,1) = 0;
mat(1:10,5,1) = 0;
mat(1:2,1,2) = 0;
mat(1:3,3,2) = 0;
mat(1:7,4,2) = 0;
mat(1:4,5,2) = 0;

% Find first non-zero element in every column
[~, firstNonZero] = max( mat ~= 0 );

% Replace leading zeros with NaN
% How to vectorize this part???
[nRows, nCols, nPlanes] = size(mat);
for j = 1 : nPlanes

   for i = 1 : nCols

       mat(1:firstNonZero(1, i, j)-1, i, j) = NaN;

   end

end
Run Code Online (Sandbox Code Playgroud)

Wol*_*fie 5

您可以使用cumsum在每列中创建累积和,然后所有前导零的累积和为零,而所有中间零都具有大于零的累积和...

mat( cumsum(mat,1) == 0 ) = NaN;
Run Code Online (Sandbox Code Playgroud)

正如评论中所建议的,如果你mat有负值,那么累积和将有可能在0以后...使用绝对值的总和代替

mat( cumsum(abs(mat),1) == 0 ) = NaN;
Run Code Online (Sandbox Code Playgroud)

请注意,默认情况下,cumsum沿第一个非单一维度操作,您可以使用可选dim参数指定维度.我已经习惯dim=1强制执行逐列操作,以防你mat的高度为1,但这是高度大于1的任何矩阵的默认值.

注意这==用于比较,您可能想要阅读为什么24.0000在MATLAB中不等于24.0000?并使用阈值进行相等比较.

  • 聪明的解决方案!我看到的唯一问题是`mat`也包含负值.有一个机会(非常小,但仍然),后来的0也有'cumsum`为0.我想人们可以做"cumsum(abs(mat))",但我们可能会想到更好的方法. (4认同)