Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Matlab 以完全矢量化的方式将矩阵中的零(或NaN)替换为前一个元素行或列_Matlab_Loops_Matrix_Vectorization - Fatal编程技术网

Matlab 以完全矢量化的方式将矩阵中的零(或NaN)替换为前一个元素行或列

Matlab 以完全矢量化的方式将矩阵中的零(或NaN)替换为前一个元素行或列,matlab,loops,matrix,vectorization,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));

我需要用前面的元素行替换矩阵中的零(或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中矩阵的索引是连续的,按列递增,因此它适用于单个行或列,但不能应用相同的确切概念,但需要使用多行进行修改,因为每个原始/列都是新开始的,必须视为独立的。我已经尽了最大的努力,用谷歌搜索了整个谷歌,但找不到出路。如果我在循环中应用同样的想法,它会变得太慢,因为我的矩阵至少包含3000行。有人能帮我解决这个问题吗?

特殊情况下,每一行中的零都是孤立的

x=[0,1,2,2,1,0;
5,6,3,0,1,2;
1,1,1,1,0,1];
%Do it column by column is easier
x=x';
rm=0;
while 1
    %fields to replace
    l=(x==0);
    %do nothing for the first row/column
    l(1,:)=0;
    rm2=sum(sum(l));
    if rm2==rm
        %nothing to do
        break;
    else
        rm=rm2;
    end
    %replace zeros
    x(l) = x(find(l)-1);
end
x=x';
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);
您可以使用的两个输出版本来定位除第一列之外的所有列中的零和NaN,然后使用将这些条目的行前值填充到这些条目中:

[ii jj] = find( (X(:,2:end)==0) | isnan(X(:,2:end)) );
X(ii+jj*size(X,1)) = X(ii+(jj-1)*size(X,1));
一般情况(每行允许连续零)

诀窍是利用矩阵
aux
,如果
X
的对应条目为0且其列号大于1,则该矩阵包含0;否则包含2个提升到列号。因此,将
cumsum
按行应用于该矩阵,取
log2
并向下舍入(矩阵
col
)给出最右边非零项到当前项的列索引,对于每一行(这是一种按行的“累积最大值”函数)。只需将列编号转换为线性索引即可(使用;也可以使用
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 = X.';                                       %'// Make a transposed copy of X
Y(isnan(Y)) = 0;
idx = find([ones(1, size(X, 1)); Y(2:end, :)]);
Y(idx(2:end)) = diff(Y(idx));
Y = reshape(cumsum(Y(:)), [], size(X, 1)).';   %'// Reshape back into a matrix

其工作原理是将输入数据视为一个长向量,应用原始解决方案,然后将结果重新整形为一个矩阵。第一列始终被视为非零,以便值不会在各行中传播。还请注意,原始矩阵被转置,以便按行的主要顺序转换为向量。

我有一个用于填充NAN的类似问题的函数。这可能会进一步减少或加速-它是从已有的代码中提取的,这些代码具有更多功能(向前/向后填充、最大距离等)

X=[
0 1 2 2 1 0
5 6 3 0 0 2
1 1 1 1 0 1
0 0 4 5 3 9
];
X(X==0)=NaN;
Y=nanfill(X,2);
Y(isnan(Y))=0
功能y=nanfill(x,尺寸)
如果nargin<2,则尺寸=1;结束
如果dim==2,y=nanfill(x',1)';返回;结束
i=find(~isnan(x(:)));
j=1:尺寸(x,1):努美尔(x);
j=j(一(x,1),1),:);
ix=最大值(代表([1;i])、差异([1;i;努梅尔(x)+1])、j(:);
y=重塑(x(ix),尺寸(x));
函数y=rep(x,次)
i=查找(次);
如果长度(i)
修改了Eitan答案的版本,以避免跨行传播值:

Y = X'; %'
tf = Y > 0;
tf(1,:) = true;
idx = find(tf);
Y(idx(2:end)) = diff(Y(idx));
Y = reshape(cumsum(Y(:)),fliplr(size(X)))';

好的,我明白你在转置上的意思。但是我不得不再次编辑这个,以插入2个初始零的大小写,并强调它们不应该继承前一行的最后一个值。很抱歉不断编辑,但特殊情况和更深层次的理解会随着我们的进行而出现…嗨,路易斯,谢谢,我担心我的示例不正确,我现在已经修复了它,只有当有一个零需要替换时,您的伟大代码才能工作,但当有更多的零需要替换时,它不会填充其他零:5,6,3,0,2;应该变成5,6,3,3,3,2;很抱歉使用了一个不充分的示例。该解决方案仅适用于n*1023以下的矩阵。对于1024或更大的矩阵,
aux
包含
inf
,这是令人印象深刻的Luis,有unfort毫无疑问,这是一个棘手的问题,如果我生成一个像X=randint(10001000)这样均匀分布的1和0的矩阵,它就可以工作,但是如果我生成X=randint(10001000100)这样的0的频率较低,它大部分会失败,实际上在ind中,你可以找到大于1000000(1000*1000)的值.该死!丹尼尔,你说得对!除了我提到的问题,当超过1024个时,索引中会出现NaN。天哪。看起来这是一个相当棘手的问题。@DanielR True。
2^1024
非常接近
realmax
,Hi Eitan,与Louis的评论相同,我可能使用了一个不正确的示例,代码也应该填充连续的零,我同意现在纠正它,对不起,谢谢你的答案。明白了。请看一下修改后的答案。也许我发现了:它是Y!我认为这个解决方案的一个限制是它会跨行传播值。例如,如果一行中的第一个和第二个值为零,那么第二个值将获得最近的非零值(来自另一行),而第一个被显式还原为零。@Charles Yep,它有一个确切的问题。感谢你的展示,我太热情了。这是一个几乎矢量化的解决方案。循环只需要处理零行,如果最多有5个连续的零,它将迭代5次。检查性能,这是一个非常快速的解决方案.Daniel,谢谢!我已经试过你的解决方案了,它实际上燃烧得很快,大约100(!)比在1000X1000矩阵上应用矢量化原始行解决方案快20倍,在2000X2000矩阵上应用矢量化原始行解决方案快20倍。嗨@Daniel R我注意到当一行在开始时有2个或更多连续的零时,代码会被阻塞,对吗?@aldo:你在使用我的代码的当前版本吗?在写answe之后不久
X = [
    0 1 2 2 1 0
    5 6 3 0 0 2
    1 1 1 1 0 1
    0 0 4 5 3 9
];

X(X == 0) = NaN;
Y = nanfill(X,2);
Y(isnan(Y)) = 0

function y = nanfill(x,dim)
if nargin < 2, dim = 1; end
if dim == 2, y = nanfill(x',1)'; return; end
i = find(~isnan(x(:)));
j = 1:size(x,1):numel(x);
j = j(ones(size(x,1),1),:);
ix = max(rep([1; i],diff([1; i; numel(x) + 1])),j(:));
y = reshape(x(ix),size(x));

function y = rep(x,times)
i = find(times);
if length(i) < length(times), x = x(i); times = times(i); end
i = cumsum([1; times(:)]);
j = zeros(i(end)-1,1);
j(i(1:end-1)) = 1;
y = x(cumsum(j));
Y = X'; %'
tf = Y > 0;
tf(1,:) = true;
idx = find(tf);
Y(idx(2:end)) = diff(Y(idx));
Y = reshape(cumsum(Y(:)),fliplr(size(X)))';