【问题标题】:MATLAB: Replace leading zeros of every column with NaNMATLAB:用 NaN 替换每列的前导零
【发布时间】:2018-09-05 08:07:34
【问题描述】:

我有一个名为 mat 的 3D 矩阵。每列可能包含也可能不包含可变数量的前导零。我需要用 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

【问题讨论】:

    标签: matlab for-loop vectorization


    【解决方案1】:

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

    mat( cumsum(mat,1) == 0 ) = NaN;
    

    如 cmets 中所建议的,如果您的 mat 具有负值,那么稍后累积总和可能会是 0... 请改用绝对值的总和

    mat( cumsum(abs(mat),1) == 0 ) = NaN;
    

    请注意,默认情况下,cumsum 沿第一个非单一维度运行,您可以使用可选的 dim 参数来指定维度。我使用dim=1 来强制按列操作,以防您的mat 的高度可能为1,但这是任何高度大于1 的矩阵的默认设置。

    注意这里使用== 进行比较,您可能需要阅读Why is 24.0000 not equal to 24.0000 in MATLAB? 并使用阈值进行相等比较。

    【讨论】:

    • 聪明的解决方案!我看到的唯一问题是mat 是否也包含负值。后面的 0 也有可能(非常小,但仍然如此)cumsum 也为 0。我想有人可以做到cumsum(abs(mat)),但我们可能会想出更好的方法。
    • @Wolfie 这是一个非常简洁的单行字。我印象深刻!
    • @Andi,取决于总和的大小/您有多少前导零,我认为性能可能因任何方法而异。在这种情况下,cumsum 可能会做很多它不需要的累加。但希望仍然相当出色!
    猜你喜欢
    • 2016-12-05
    • 1970-01-01
    • 2018-01-07
    • 1970-01-01
    • 2015-03-13
    • 1970-01-01
    • 1970-01-01
    • 2013-03-12
    • 1970-01-01
    相关资源
    最近更新 更多