Как учесть високосные годы?
У меня есть некоторые сомнения по поводу високосных лет, как я могу быть уверен, что с помощью такой формулы
add.years= function(x,y){
if(!isTRUE(all.equal(y,round(y)))) stop("Argument \"y\" must be an integer.\n")
x <- as.POSIXlt(x)
x$year <- x$year+y
as.Date(x)
}
это будет учитывать високосные годы, когда, например, добавится 100 лет к моему набору данных? Как я могу контролировать это?
У меня есть набор данных временного ряда с 50-летними наблюдениями:
date obs
1995-01-01 1.0
1995-01-02 2.0
1995-01-03 2.5
...
2045-12-30 0.2
2045-12-31 0.1
набор данных +100 лет
date obs
2095-01-01 1.0
2095-01-02 2.0
2095-01-03 2.5
...
2145-12-30 0.2
2145-12-31 0.1
После основной проверки я заметил, что количество строк одинаково как для исходного, так и для 100 лет после набора данных. Я не уверен, что то, что было до 29 февраля в високосный год, будет теперь значением obs для 1 марта в не високосный год и т. Д.
Я могу проверить високосные годы, используя из библиотеки chron функцию leap.year, однако я хотел бы знать, есть ли более простой способ сделать это, чтобы убедиться, что строки с проходными днями 29 февраля, которые не существуют 100 лет спустя будут удалены, и новые дни 29 февраля будут добавлены со значениями NA.
4 ответа
Вы можете проверить, является ли год високосным leap_year
от lubridate
,
years <- 1895:2005
years[leap_year(years)]
Этот пакет также будет обрабатывать не генерации невозможного 29 февраля.
ymd("2000-2-29") + years(1) # NA
ymd("2000-2-29") %m+% years(1) # "2001-02-28"
%m+%
Оператор "добавить месяцы", как упомянуто @VitoshKa, откатывает дату обратно к концу предыдущего месяца, если фактический день не существует.
Следуя предложению DarkDust и Dirk Eddelbuettel, вы можете легко бросить свой собственный leap_year
функция:
leap_year <- function(year) {
return(ifelse((year %%4 == 0 & year %%100 != 0) | year %%400 == 0, TRUE, FALSE))
}
и применить его к векторным данным:
years = 2000:2050
years[leap_year(years)]
[1] 2000 2004 2008 2012 2016 2020 2024 2028 2032 2036 2040 2044 2048
Год является високосным, если:
- Делится на 4.
- Нет, если это делится на 100.
- Но если это делится на 400.
Вот почему 2000 год был високосным (хотя он делится на 100, он также делится на 400).
Но, как правило, если у вас есть библиотека, которая может выполнять вычисления даты / времени, используйте ее. Это очень сложно сделать эти вычисления и легко сделать неправильно, особенно с учетом древних дат (календарных реформ) и часовых поясов.
Ваши подозрения действительно верны:
x <- as.POSIXlt("2000-02-29")
y <- x
y$year <- y$year+100
y
#[1] "2100-03-01"
Странно то, что другие части y
остаются неизменными, поэтому вы не можете использовать их для сравнения:
y$mday
#[1] 29
y$mon
#[1] 1
Но вы можете использовать strftime
:
strftime(x,"%d")
#[1] "29"
strftime(y,"%d")
#[1] "01"
Так как насчет:
add.years <- function(x,y){
if(!isTRUE(all.equal(y,round(y)))) stop("Argument \"y\" must be an integer.\n")
x.out <- as.POSIXlt(x)
x.out$year <- x.out$year+y
ifelse(strftime(x,"%d")==strftime(x.out,"%d"),as.Date(x.out),NA)
}
Затем вы можете установить свои данные с помощью [
а также is.na
чтобы избавиться от дубликатов дат 1 марта. Хотя эти даты кажутся последовательными, вы можете рассмотреть решение, которое использует seq.Date
и избегайте сброса данных.