필터 지우기
필터 지우기

How to remove February 29th for leap years in a daily time series over 43 years?

조회 수: 15 (최근 30일)
I have an array of values (x) representing daily data for 43 years (1979-2021) where size(x)=15706
I rearranged the data to have a matrix with years as rows and days as columns.
% some x --> keep only multiple of 365 days (removes last 11 days)
x = x(1:365*43).';
% reshape x to have years as rows and days as columns
x_matrix = reshape(x,365,[]).'
However, this is problematic for leap years since now my columns in x_matrix are not aligned with a given day. Indeed, x_matrix(year n, 1) is not always January 1 but is shifted toward later in January as years pass.
My data represents year 1979-2021 where 1980, 1984, 1988, 1992, 1996, 2000, 2004, 2008, 2012, 2016, 2020 are leap years.
How can I remove the last day of February for each leap year to have x_matrix align for each year with a given day where x_matrix(year n, 1) is always January 1?
Is there a useful function for that somewhere?
Thank you
  댓글 수: 5
dpb
dpb 2022년 6월 1일
OK, that's one reason I hadn't thought of for a rectangular array...if you don't want to regularize with missing data for the non-leap years, then simply
t=datetime(1979,1,1):days(1):datetime(2021,12,31);
isNotLeapDay=~(month(t)==2 & day(t)==29);
data=data(isNotLeapDay);
That's assuming a vector of the data before trying to reshape into an array.
I think I'd still keep the full data set and just extract as above for the special purpose...

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

채택된 답변

Jon
Jon 2022년 6월 1일
편집: Jon 2022년 6월 1일
I fully support @dpb suggestions regarding working with timetables. However for purposes of making your graphic, you could do this
% define example data
x = rand(15706,1);
% make datetimes corresponding to data
t1 = datetime(1979,1,1);
t2 = datetime(2021,12,31);
t = t1:t2;
% find all the leap days and remove them
idl = month(t)==2 & day(t)==29;
xClean = x(~idl);
% make matrix with rows as days and years as columns
X = reshape(xClean,365,43)
  댓글 수: 1
Steven Lord
Steven Lord 2022년 6월 1일
Another way to do this, assuming you just know how many rows the data has and what the initial date is (without knowing the ending date ahead of time) you could use a datetime and a duration or calendarDuration array.
t1 = datetime(1979,1,1);
t2 = datetime(2021,12,31);
tv1 = t1:t2; % start and end known
n = 15706;
tv2 = t1 + days(0:n-1); % start and number of steps known
tv3 = t1 + caldays(0:n-1); % start and number of steps known
tv1(end), tv2(end), tv3(end)
ans = datetime
31-Dec-2021
ans = datetime
31-Dec-2021
ans = datetime
31-Dec-2021
isequal(tv1, tv2)
ans = logical
1
isequal(tv1, tv3)
ans = logical
1
Now locate leap days as before.
isleap = @(dt) month(dt) == 2 & day(dt) == 29;
tv1(isleap(tv1)).'
ans = 11×1 datetime array
29-Feb-1980 29-Feb-1984 29-Feb-1988 29-Feb-1992 29-Feb-1996 29-Feb-2000 29-Feb-2004 29-Feb-2008 29-Feb-2012 29-Feb-2016 29-Feb-2020

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

추가 답변 (1개)

James Tursa
James Tursa 2022년 6월 1일
편집: James Tursa 2022년 6월 1일
To get rid of the leap days, you can use evenly spaced indexing since the number of days between leap days is constant for your time span. Since index 1 corresponds to Jan 1, 1979, that means the first leap day is Feb 29, 1980 which is index 365+31+29 = 425. The next leap day will be 4*365+1 = 1461 days later. So the code to get rid of the leap days for your data is (do this prior to reshaping):
x(425:1461:end) = [];

카테고리

Help CenterFile Exchange에서 Dates and Time에 대해 자세히 알아보기

제품


릴리스

R2021a

Community Treasure Hunt

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

Start Hunting!

Translated by