Matlab Заполнить предыдущее значение, если отсутствует значение (или ноль)

У меня есть вектор, содержащий временной ряд с разными значениями и некоторыми отсутствующими значениями между ними, которые установлены равными нулю:

X=[0,0,2,0,5,0,0,0,4,0];

Я хочу создать новый вектор, в котором пропущенные значения (нули) заполняются предыдущим значением, если оно существует, чтобы я получил новый вектор, похожий на:

Z=[0,0,2,2,5,5,5,5,4,4];

Я просматривал справку Matlab и подобные форумы, чтобы найти удобную и подходящую функцию, которая решила бы это для меня с помощью однострочного решения или аналогичного, но мне это не удалось. Я могу решить проблему, выполнив несколько различных шагов, как показано ниже, но я предполагаю, что должно быть лучшее и более простое решение?

Текущее решение:

X=[0,0,2,0,5,0,0,0,4,0];
ix=logical(X);
Y = X(ix);
ixc=cumsum(ix);
Z=[zeros(1,sum(~logical(ixc))) Y(ixc(logical(ixc)))];

Это помогает, но кажется слишком сложным решением простой проблемы, так что может ли кто-нибудь помочь мне с лучшим решением? Спасибо.


person hgus1294    schedule 08.09.2011    source источник


Ответы (3)


Вот несколько более простая версия с использованием cumsum:

X=[0,0,2,0,5,0,0,0,4,0];

%# find the entries where X is different from zero
id = find(X); 

%# If we want to run cumsum on X directly, we'd 
%# have the problem that the non-zero entry to the left
%# be added to subsequent non-zero entries. Thus, 
%# subtract the non-zero entries from their neighbor 
%# to the right 
X(id(2:end)) = X(id(2:end)) - X(id(1:end-1));

%# run cumsum to fill in values from the left
Y = cumsum(X)

Y =
     0     0     2     2     5     5     5     5     4     4
person Jonas    schedule 08.09.2011
comment
Я согласен, это небольшое улучшение моей версии. Я оставлю вопрос открытым еще немного и посмотрю, получу ли я какие-либо альтернативные решения, иначе я приму это. Спасибо. - person hgus1294; 08.09.2011
comment
Иду с этой версией. Благодарю вас! Чтобы еще немного «улучшить» решение, вы, очевидно, можете изменить 3-ю строку на X(id(2:end)) = diff(X(id)); :-) - person hgus1294; 09.09.2011

Вот немного чего написал. Это помогает?

% INPUT: the array you would like to populate
% OUTPUT: the populated array

function popArray = populate(array)

popArray = array;

% Loops through all the array elements and if it equals zero, replaces it
% with the previous element
%
% Since there is no element before the first to potentially populate it, this
% starts with the second element.
for ii = 2:length(popArray)
    if array(ii) == 0;
        popArray(ii)= popArray(ii-1);
    end
end

disp(popArray);
person Jenna Zeigen    schedule 08.09.2011
comment
Я нахожу это намного более читаемым, чем решение OP; было бы интересно сравнить их скорость, если это проблема здесь? - person Jonas Heidelberg; 08.09.2011
comment
Спасибо. Я бы очень хотел держаться подальше от циклов. Мои фактические векторы/матрицы намного больше, чем в этом примере, поэтому производительность является фактором. - person hgus1294; 08.09.2011
comment
ты прав. циклы в Matlab не оптимальны. хотя нет смысла не пытаться помочь. я буду продолжать думать об этом с массивами. - person Jenna Zeigen; 09.09.2011

Позвольте мне предложить другое векторизованное решение (хотя мне нравится решение @Jonas лучше):

X = [0 0 2 0 5 0 0 0 4 0]

id = find(X);
X(id(1):end) = cell2mat( arrayfun(@(a,b)a(ones(1,b)), ...
    X(id), [diff(id) numel(X)-id(end)+1], 'UniformOutput',false) )
person Amro    schedule 08.09.2011
comment
Хороший, но я думаю, что согласен с тем, что у @Jonas пока есть предпочтительное решение. Спасибо. - person hgus1294; 08.09.2011