Repeat previous row if condition

조회 수: 5 (최근 30일)
Dave
Dave 2015년 2월 18일
댓글: David Young 2015년 2월 19일
Hi, I have an nx2 matrix, the first column gives the order, 10 20 30 40 and then repeats again, but if there is no observation it jumps to the next (eg if no 40 then it has 10 20 30 10 20 30 40 ....)
What I need is to repeat what is in the previous row in the case where there is no last (40) or next to last (30):
A) If there is no 40 but there is 30, then create row 40 and repeat element of 30 in the second column.
B) If there is no 40 and no 30 but there is 20, then create row 30 and 40 and repeat element of 20 in the second column.
C) If there is no 30 but there is 20, then creaste row 30 and repeat element of 20 in the second column.
I give an example with matrix M1 below for the 3 cases above.
Original matrix M1 is 12x2
M1 = [
10 44;
20 72;
30 21;
40 13;
10 32;
20 26;
30 55;
10 23;
20 98;
10 36;
20 84;
40 22]
New matrix M2 is 16x2
M2 = [
10 44;
20 72;
30 21;
40 13;
10 32;
20 26;
30 55;
40 55;
10 23;
20 98;
30 98;
40 98;
10 36;
20 84;
30 84;
40 22]
In M2 since the first cycle 10 20 30 40 in M1 was ok no additions.
But the second cycle in M1 has no 40, so M2 creates the row 40 and repeats element of 30.
The third cycle has no 30 nor 40, but has 20, so creates 30 and 40 and repeats element of 20.
The fourth cycle has no 30 so creates 30 and repeats element of 20 (note 40 is not touched)
Help please
  댓글 수: 1
Dave
Dave 2015년 2월 18일
Thanks dpb, I re made the problem perhaps it is easier now:
I know in advance the dimensions of my target matrix M2 (16x2) so I'll use this.
I re-made M1 to have that dimension, so it is always 10 20 30 40. But when there is no element in the second column, it reads NaN
So now the M1, say M1b is
M1b=[
10 44;
20 72;
30 21;
40 13;
10 32;
20 26;
30 55;
40 NaN;
10 23;
20 98;
30 NaN;
40 NaN;
10 36;
20 84;
30 NaN;
40 22]
So my target is still matrix M2, which needs to replace nan with previous ONLY if the criteria holds. The nan replacing only holds for the 30 and 40 cases. Eg if there is nan in 20 you just leave it as nan.

댓글을 달려면 로그인하십시오.

채택된 답변

David Young
David Young 2015년 2월 18일
편집: David Young 2015년 2월 18일
% Parameters
cycleLength = 4; % number of rows in a cycle
indexMult = 10; % multiplier for index within cycle
orders = M1(:, 1);
% get output row indexes
ind = cycleLength * (cumsum(orders == indexMult) - 1) + orders/indexMult;
% number of rows in output matrix, so that have complete cycle at end
indlast = ceil(ind(end)/cycleLength) * cycleLength;
indall = 1:indlast;
% set up output matrix and allocate adjusted indices to first column
M2 = zeros(indlast, 2);
M2(:,1) = indexMult * (mod(indall-1, cycleLength) + 1);
% put data into correct rows of second column
M2(ind, 2) = M1(:, 2);
% propagate missing data - first element in each gap
jumps = diff([ind; indlast+1]);
gappos = ind(jumps > 1);
M2(gappos+1, 2) = M2(gappos, 2);
% propagate missing data - second element in double gap
gappos = ind(jumps > 2);
M2(gappos+2, 2) = M2(gappos+1, 2);
% assume no gaps longer than 2 elements
  댓글 수: 3
David Young
David Young 2015년 2월 19일
Your question only said that 30 and/or 40 might be missing. It's easy to generalise to 20 missing too - edit coming up - but I'm not sure how you can deal with 10 missing, as there's then nothing to indicate the start of a new cycle.
David Young
David Young 2015년 2월 19일
Oh hang on - what exactly do you want to happen if 20,30 and 40 are missing in a cycle? All NaN, or all copies of the 10 value, or something else? I'll wait to make a change till I know what the result needs to be.

댓글을 달려면 로그인하십시오.

추가 답변 (1개)

dpb
dpb 2015년 2월 18일
I've no magic bullet but
>> idx=find((diff([0; M(:,1)])>0 & diff([0; M(:,1)])~=10) | ...
(diff([0; M(:,1)])<0 & diff([0; M(:,1)])~=-30) )
ans =
8
10
12
Gives you the indices in the vector of the locations missing one or more values. Best I got is to then walk thru this array and check the difference between that location and the prior and use that to control the arguments to a repmat call.
One thing you can do is to build a new M array a priori that is clean for all the first column(*) and as you're working thru the existing vector that's the target for the new rows, meanwhile you copy those that aren't missing as you go until get to next element in the above list.
Bound to be a way accumarray could help but I've got other commitments that prevent spending more time at the moment, sorry...
(*) i.e., if the 10 is always present, then the new array could be built as
nReps=sum(M(:,1)==10); % how many groups are there?
N=zeros(nReps,2); % a new full-length array
N(:,1)=repmat([10:10:40].',nReps,1); % fill the first column

카테고리

Help CenterFile Exchange에서 Creating and Concatenating Matrices에 대해 자세히 알아보기

태그

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by