How to convert consecutive numbers in NaN?

Hi there, I have a matrix (8760x18) with random numbers. the values have valid zeros and invalid zeros. The invalid zeros are continually presented, I mean postion (12 13 14 15 16 . . . 21) or any position between 1 and 8760. The valid zeros have randomly positions, I mean position (9 has zero value) but the position before and after are numbers > 0. To understand better I did an example, which is varaible (y). It has 10 continually invalid zeros that I would like become NaN, but it has also valid zeros that I would like to keep. My idea is the next -> If there is more than fice consecutive zeros, become NaN, if not, leave 0's.
|-- invalid zeros--| |valid|
y= [1 2 3 5 2 6 4 8 0 5 2 0 0 0 0 0 0 0 0 0 0 1 2 5 6 9 8 74 0 0 0 32 8 4 6 1 10 2]';
I already try to do the next code, but the result is:
for i=1:length(y)
if y((i)+5,1)==0 & y((i)+4,1)==0 & y((i)+3,1)==0 & y((i)+2,1)==0 & y((i)+1,1)==0
y(i,1) = NaN;
end
end
y= [1 2 3 5 2 6 4 8 0 5 NaN NaN NaN NaN NaN NaN NaN 0 0 0 0 0 2 5 6 9 8 74 0 0 0 32 8 0 6 1 10 0];
And like the last number is zero, obviusly get an error that exceeds array bounds, but coudn't fix it.
Index in position 1 exceeds array bounds (must not exceed 38).
Error in analise_dados_mp25 (line 71)
if y((i)+5,1)==0 & y((i)+4,1)==0 & y((i)+3,1)==0 & y((i)+2,1)==0 & y((i)+1,1)==0
Thanks in advanced.

 Accepted Answer

Try this —
y = [1 2 3 5 2 6 4 8 0 5 2 0 0 0 0 0 0 0 0 0 0 1 2 5 6 9 8 74 0 0 0 32 8 4 6 1 10 2]';
y = [y;y;y; zeros(8,1)]; % Extend 'y'
y = 122×1
1 2 3 5 2 6 4 8 0 5
z5 = strfind(y(:)', [0 0 0 0 0]); % Start Indices Of Consecutive 'zero(1,5)'
dz5 = [1 find(diff(z5)>1)+1 numel(z5)]; % Index Differences
for k = 1:numel(dz5)-1 % Do Replacements
y(z5(dz5(k):dz5(k+1))-1) = NaN;
end
for k = 1:20:numel(y) % Check Result
row = sprintf([repmat('%d ',1,20) '\n'],y(k:min(k+19,numel(y))))
end
row =
'1 2 3 5 2 6 4 8 0 5 NaN NaN NaN NaN NaN NaN 0 0 0 0 '
row =
'0 1 2 5 6 9 8 74 0 0 0 32 8 4 6 1 10 2 1 2 '
row =
'3 5 2 6 4 8 0 5 NaN NaN NaN NaN NaN NaN 0 0 0 0 0 1 '
row =
'2 5 6 9 8 74 0 0 0 32 8 4 6 1 10 2 1 2 3 5 '
row =
'2 6 4 8 0 5 NaN NaN NaN NaN NaN NaN 0 0 0 0 0 1 2 5 '
row =
'6 9 8 74 0 0 0 32 8 4 6 1 10 NaN NaN NaN NaN 0 0 0 '
row = '0 0 '
I made it as robust as I could.

6 Comments

Thanks, the code works very well. But not all zeros became NaN. I am looking for that if there are more than five zeros in a row, they are all NaN. I am sure I did not know how to elaborate the question.
| become NaN | |not NaN|
y = [1 2 3 5 2 6 4 8 0 5 2 0 0 0 0 0 0 0 0 0 0 1 2 5 6 9 8 74 0 0 0 32 8 4 6 1 10 0]';
I am now not certain what you want to do.
It may be necessary to experiment with my code to get the result you want, since I may not understand that correctly.
Try this modification —
y = [1 2 3 5 2 6 4 8 0 5 2 0 0 0 0 0 0 0 0 0 0 1 2 5 6 9 8 74 0 0 0 32 8 4 6 1 10 2]';
y = [y;y;y;zeros(8,1)]; % Extend 'y'
nz = find(y ~= 0);
if nz(1)>1
nz = [1; nz];
elseif nz(end) ~= numel(y)
nz = [nz; numel(y)+1];
end
dnz = find(diff(nz)>=5);
idx = [nz(dnz)+1 nz(dnz+1)-1];
for k = 1:size(idx,1)
y(idx(k,1):idx(k,2)) = NaN;
end
for k = 1:20:numel(y) % Check Result
row = sprintf([repmat('%d ',1,20) '\n'],y(k:min(k+19,numel(y))))
end
row =
'1 2 3 5 2 6 4 8 0 5 2 NaN NaN NaN NaN NaN NaN NaN NaN NaN '
row =
'NaN 1 2 5 6 9 8 74 0 0 0 32 8 4 6 1 10 2 1 2 '
row =
'3 5 2 6 4 8 0 5 2 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN 1 '
row =
'2 5 6 9 8 74 0 0 0 32 8 4 6 1 10 2 1 2 3 5 '
row =
'2 6 4 8 0 5 2 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN 1 2 5 '
row =
'6 9 8 74 0 0 0 32 8 4 6 1 10 2 NaN NaN NaN NaN NaN NaN '
row = 'NaN NaN '
Here, all occurrences of five or more zeros in a row are NaN. Occurrences of less than five zeros in a row are not NaN.
Star Strider, it worked perfectly. Thanks a lot. One more question, I didn't understand the follows lines: I mean, I can see what it does, but not sure about the process.
nz = find(y ~= 0); % here find numbers differents of zero
if nz(1)>1 % I don't understand
nz = [1; nz]; % I don't understand
elseif nz(end) ~= numel(y) % Here I see that if is different that the final number, add one more.
nz = [nz; numel(y)+1];
end
dnz = find(diff(nz)>=5); % I read that diff is the differente between x values and x values, but not sure in this exmanple.
idx = [nz(dnz)+1 nz(dnz+1)-1]; % I dont understand.
As I told you, the code worked perfectly. Just I would like to understand better. I would like to learn :). Thanks a lot again.
Thank you!
No worries! I will explain as best I can how it works.
The if block checks the starting and ending indices of ‘nz’ to be certain that all the elements of ‘y’ are accounted for in it. So if the first element of ‘nz’ is not 1, the if block concatenates a 1 to the beginning of it, in order to correct for any zeros at the beginning of the vector. If the last element is not the end of the vector, for the same reason, the if block concatenates that value to the end of it and increments it by 2 because the code later takes the differences in ‘nz’ to determine the correct indices for the NaN replacement. The if block is necessary for ‘dnz’ to produce accurate results.
The ‘dnz’ (‘differences in ‘nz’) assignment finds differences between the consecutive nonzero element indices that are greater than or equal to 5. This is to meet the design requirements.
The ‘idx’ matrix are the beginning and ending elements of the vector segments to be replaced by NaN. They are used in the for loop that follows it. It made it easier for me to troubleshoot the code. I could have omitted it and instead written the loop as:
for k = 1:size(idx,1)
y(nz(dnz(k))+1:nz(dnz(k)+1)-1) = NaN;
end
with the same effect (I tested it to be certain). It was just easier to write the matrix and then refer to elements of it in the loop.
.
Thanks a lot, Star Strider! I got it much better. Amazing! Thank you.
As always, my pleasure!

Sign in to comment.

More Answers (0)

Categories

Find more on Interpolation of 2-D Selections in 3-D Grids in Help Center and File Exchange

Community Treasure Hunt

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

Start Hunting!