我需要用行中的前一个元素替换矩阵中的零(或NaN),所以基本上我需要这个Matrix 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行。有人可以帮我解决这个问题吗?
答案 0 :(得分:1)
在每行中分隔零的特殊情况
您可以使用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
答案 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
这通过将输入数据视为长向量,应用原始解决方案然后将结果重新整形回矩阵来工作。始终将第一列视为非零,以便值不会在整个行中传播。另请注意,原始矩阵是转置的,以便将其转换为行主要顺序的向量。
答案 2 :(得分:0)
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';
答案 3 :(得分:0)
我有一个函数用于填充NaNs的类似问题。这可能会被削减或进一步加速 - 它是从具有更多功能(前向/后向填充,最大距离等)的预先存在的代码中提取的。
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));
答案 4 :(得分:0)
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)))';