matlab - 以完全矢量化的方式用前一个元素逐行或逐列替换矩阵中的零(或 NAN)

标签 matlab loops matrix vectorization

我需要用前一个元素按行替换矩阵中的零(或 NaN),所以基本上我需要这个矩阵 X

[0,1,2,2,1,0;  
5,6,3,0,0,2;  
0,0,1,1,0,1]  

变成这样:

[0,1,2,2,1,1;  
5,6,3,3,3,2;  
0,0,1,1,1,1],  

请注意,如果第一行元素为零,它将保持原样。

我知道这已经以向量化的方式解决了单个行或列向量,这是最好的方法之一:

id = find(X);         
X(id(2:end)) = diff(X(id));       
Y = cumsum(X)  

问题是 Matlab/Octave 中矩阵的索引是连续的,并且按列递增,因此它适用于单个行或列,但不能应用相同的概念,但需要用多行进行修改,因为每个行raw/column 重新开始,必须被视为独立的。我已经尽了最大努力并搜索了整个谷歌,但找不到出路。如果我在循环中应用同样的想法,它会变得太慢,因为我的矩阵至少包含 3000 行。谁能帮我解决这个问题?

最佳答案

每行中零被隔离的特殊情况

您可以使用 find 的双输出版本来做到这一点在除第一列之外的所有列中找到零和 NaN,然后​​使用 linear indexing用它们的行前值填充这些条目:

[ii jj] = find( (X(:,2:end)==0) | isnan(X(:,2:end)) );
X(ii+jj*size(X,1)) = X(ii+(jj-1)*size(X,1));

一般情况(每行允许连续零)

X(isnan(X)) = 0; %// handle NaN's and zeros in a unified way
aux = repmat(2.^(1:size(X,2)), size(X,1), 1) .* ...
    [ones(size(X,1),1) logical(X(:,2:end))]; %// positive powers of 2 or 0
col = floor(log2(cumsum(aux,2))); %// col index
ind = bsxfun(@plus, (col-1)*size(X,1), (1:size(X,1)).'); %'// linear index
Y = X(ind);

诀窍是利用矩阵aux,如果X对应的条目为0且其列号大于1,则包含0;否则包含 2 提升到列号。因此,对该矩阵逐行应用 cumsum,取 log2 并向下舍入(矩阵 col)给出最右边的非零条目的列索引直到当前条目,对于每一行(所以这是一种按行的“累积最大”函数。)它只剩下从列号转换为线性索引(使用 bsxfun ;也可以使用 sub2ind) 并用它来索引 X

这仅对中等大小的 X 有效。对于大尺寸,代码使用的 2 的幂很快接近 realmax 并且导致不正确的索引。

例子:

X =
     0     1     2     2     1     0     0
     5     6     3     0     0     2     3
     1     1     1     1     0     1     1

给予

>> Y
Y =
     0     1     2     2     1     1     1
     5     6     3     3     3     2     3
     1     1     1     1     1     1     1

关于matlab - 以完全矢量化的方式用前一个元素逐行或逐列替换矩阵中的零(或 NAN),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21068256/

相关文章:

c++ - 获取由 vector 的 vector 表示的矩阵的第一列

java - 着色器/矩阵问题 - 看不到对象

matlab - 动态规划 - 递归实现

php - 我无法从已经使用 GROUP BY 的表中循环记录

python - 从 NumPy 矩阵中满足条件的每一行中取 N 个第一个值

Ruby:for 循环和 each 循环有什么区别?

javascript - 如何通过缓动增加 javascript 循环延迟

matlab - 运行 GUI 需要在 GUIDE 中打开 .fig 文件

Matlab - 直方图边缘和切断

c - 在 mex 上使用整数数组