# Monthly maximum in data

10 views (last 30 days)
Max Langworthy on 22 Jan 2021
Edited: Max Langworthy on 25 Jan 2021
I am trying to write a function that finds all the monthly maxima for a whole dataset. I am very new to programming and MATLAB. This is an example of a loop similar to the one i am doing
for i=1:100
year(i)=max(d(i))
end
I tried to use this code and copy and paste it for every year in the dataset, because I don't know how to use timetable or double 'for' loops, but I received an error message telling me that the left and right sides have different numbers of elements. How could I rewrite this to give me the function I'm looking for?
##### 1 CommentShowHide None
dpb on 22 Jan 2021
Don't beat head against a wall, convert to a timetable and then use retime
That way will be about two or three lines of code -- there are clear examples in the doc -- give it a go and post back your efforts and where get stuck.

Kelly Kearney on 23 Jan 2021
While you could do this with find, using the second output of max is a bit quicker.
% Some fake data similar to yours
t = datetime(2018,1,1:500)';
rsq = [rand(500,1) day(t) month(t) year(t)];
% Find max...
imax = zeros(12,1);
for im = 1:12
tmp = rsq(:,1); % temporary copy of the data
tmp(rsq(:,3)~=im) = -Inf; % anything not matching this month set low
[~,imax(im)] = max(tmp); % returns index of max value
end
maxval = rsq(imax,:)

### More Answers (1)

dpb on 24 Jan 2021
t = datetime(2018,1,1:500)';
rsq = [rand(500,1) day(t) month(t) year(t)];
Alternatively for the same data structure above:
maxVals=splitapply(@max,rsq(:,1),findgroups(rsq(:,3)));
This solution and the one above both will be a global max over all data in the array of the given month -- if there are multiple years of data and it isn't desired to analyze all months of all years as a composite, then must group by both year and month:
[g,idy,idm]=findgroups(rsq(:,4),rsq(:,3));
maxVals=splitapply(@max,rsq(:,1),g)];
For a given set of values here, this resulted in:
[idm idy maxVals]
ans =
1.00 2018.00 0.98
2.00 2018.00 0.97
3.00 2018.00 0.99
4.00 2018.00 0.99
5.00 2018.00 1.00
6.00 2018.00 0.92
7.00 2018.00 0.99
8.00 2018.00 0.91
9.00 2018.00 0.97
10.00 2018.00 0.96
11.00 2018.00 0.95
12.00 2018.00 0.99
1.00 2019.00 0.93
2.00 2019.00 0.96
3.00 2019.00 1.00
4.00 2019.00 0.99
5.00 2019.00 0.96
>>
in a tabular form with the grouping id variables from findgroups. I used format bank to avoid the automatic scaling of default format but that does add the two decimal points onto the integer values...
A table isn't really any harder--starting from the array above,
trsq=array2table(rsq,'VariableNames',{'Data','Day','Month','Year'});
tmaxVals=rowfun(@max,trsq,'InputVariables','Data', ...
'GroupingVariables',{'Year','Month'}, ,,, ...
'OutputVariableNames',{'GroupMax'});
for the same realization of the random data as above this gives:
>> format short,format compact
ans =
8×4 table
Data Day Month Year
_______ ___ _____ ____
0.30596 1 1 2018
0.91988 2 1 2018
0.80037 3 1 2018
0.66754 4 1 2018
0.25832 5 1 2018
0.95717 6 1 2018
0.40822 7 1 2018
0.51435 8 1 2018
>> tmaxVals =
17×4 table
Year Month GroupCount GroupMax
____ _____ __________ ________
2018 1 31 0.98046
2018 2 28 0.96657
2018 3 31 0.99294
2018 4 30 0.99388
2018 5 31 0.99522
2018 6 30 0.92159
2018 7 31 0.98775
2018 8 31 0.91045
2018 9 30 0.9694
2018 10 31 0.95942
2018 11 30 0.9504
2018 12 31 0.98866
2019 1 31 0.92582
2019 2 28 0.95508
2019 3 31 0.99525
2019 4 30 0.99393
2019 5 15 0.95888
>>