考虑到闰年,如何将一年的每日数据复制到多年?
How to replicate one year daily data to multiple years taking into account leap years?
我有一年的 365 个每日值。现在我想复制 2014 年到 2018 年的这些值。如果有闰年,将 2 月 29 日设为 2 月 28 日和 3 月 1 日的平均值。
我怎样才能自动执行此操作?这是我到目前为止所拥有的。非常感谢您!
library(xts)
set.seed(1)
myday <- seq(1, 365, by = 1)
myvalue <- rnorm(length(myday))
mydata <- data.frame(myday, myvalue)
head(mydata)
#> myday myvalue
#> 1 1 -0.6264538
#> 2 2 0.1836433
#> 3 3 -0.8356286
#> 4 4 1.5952808
#> 5 5 0.3295078
#> 6 6 -0.8204684
myyear <- seq(2014, 2018, by = 1)
myyear
#> [1] 2014 2015 2016 2017 2018
leapyearvalue <- 0.5 * (mydata$myvalue[mydata$myday == 28] + mydata$myvalue[mydata$myday == 29])
leapyearvalue
#> [1] -0.9744512
repdata <- coredata(mydata)[rep(seq(nrow(mydata)), length(myyear)), ]
head(repdata)
#> myday myvalue
#> 1 1 -0.6264538
#> 2 2 0.1836433
#> 3 3 -0.8356286
#> 4 4 1.5952808
#> 5 5 0.3295078
#> 6 6 -0.8204684
编辑:添加了 2014-18 年的输出。
这里有一个函数可以帮助解决这个问题。输入年份和 day_num(对于那一年),它会输出该日期的标准值。我假设您希望闰年的 4 月 1 日输出标准年的 4 月 1 日,这需要从第 92 天(闰年)转移到 365 天年中的第 91 天。
daily_value <- function(year, day_num) {
leap <- year %in% c(2008, 2012, 2016, 2020, 2024)
leap_day_val <- 0.5 * (mydata[59,2] + mydata[60,2])
day_num_adj <- day_num + ifelse(leap & day_num >= 61, -1, 0)
day_value <- ifelse(leap & day_num == 60,
leap_day_val,
mydata[day_num_adj,2])
day_value
}
测试
mydata[59,]
# myday myvalue
#59 59 0.5697196
daily_value(2016,59)
#[1] 0.5697196
mydata[59:60,]
# myday myvalue
#59 59 0.5697196
#60 60 -0.1350546
mean(c(0.5697196, -0.1350546))
#[1] 0.2173325
daily_value(2016,60)
#[1] 0.2173325
# Day 61 of 2016 was March 1, which is day 60 in years with 365 days
mydata[60,]
# myday myvalue
#60 60 -0.1350546
daily_value(2016,61)
#[1] -0.1350546
现在,我们可以将其应用于 2014-18 年的所有日子:
output <- data.frame(dates = seq.Date(as.Date("2014-01-01"), as.Date("2018-12-31"), 1))
output$day_of_year = lubridate::yday(output$dates)
output$value = daily_value(lubridate::year(output$dates), output$day_of_year)
subset(output, day_of_year > 58 & day_of_year <= 61)
# dates day_of_year value
#59 2014-02-28 59 0.5697196
#60 2014-03-01 60 -0.1350546
#61 2014-03-02 61 2.4016178
#424 2015-02-28 59 0.5697196
#425 2015-03-01 60 -0.1350546
#426 2015-03-02 61 2.4016178
#789 2016-02-28 59 0.5697196
#790 2016-02-29 60 0.2173325 # Leap day gets avg of 2/28 and 3/01
#791 2016-03-01 61 -0.1350546 # Rest of leap year shifted back one day
#1155 2017-02-28 59 0.5697196
#1156 2017-03-01 60 -0.1350546
#1157 2017-03-02 61 2.4016178
#1520 2018-02-28 59 0.5697196
#1521 2018-03-01 60 -0.1350546
#1522 2018-03-02 61 2.4016178
您可以使用 lubridate
中的 leap_year
函数。我已经编写了两个函数来自动执行您的任务:
set.seed(1)
mydata <- rnorm(365)
generate_days <- function(years){
unlist(sapply(years, function(x) {
if (lubridate::leap_year(x)){
1:366} else {
1:365}
}))
}
generate_data <- function(years, my_data){
unlist(sapply(years, function(x) {
if (lubridate::leap_year(x)){
c(my_data[1:59], mean(my_data[59:60]), my_data[60:365])} else {
my_data}
}))
}
df <- data.frame(days = generate_days(2014:2018),
value = generate_data(2014:2018, mydata))
df[730+60,]
我有一年的 365 个每日值。现在我想复制 2014 年到 2018 年的这些值。如果有闰年,将 2 月 29 日设为 2 月 28 日和 3 月 1 日的平均值。
我怎样才能自动执行此操作?这是我到目前为止所拥有的。非常感谢您!
library(xts)
set.seed(1)
myday <- seq(1, 365, by = 1)
myvalue <- rnorm(length(myday))
mydata <- data.frame(myday, myvalue)
head(mydata)
#> myday myvalue
#> 1 1 -0.6264538
#> 2 2 0.1836433
#> 3 3 -0.8356286
#> 4 4 1.5952808
#> 5 5 0.3295078
#> 6 6 -0.8204684
myyear <- seq(2014, 2018, by = 1)
myyear
#> [1] 2014 2015 2016 2017 2018
leapyearvalue <- 0.5 * (mydata$myvalue[mydata$myday == 28] + mydata$myvalue[mydata$myday == 29])
leapyearvalue
#> [1] -0.9744512
repdata <- coredata(mydata)[rep(seq(nrow(mydata)), length(myyear)), ]
head(repdata)
#> myday myvalue
#> 1 1 -0.6264538
#> 2 2 0.1836433
#> 3 3 -0.8356286
#> 4 4 1.5952808
#> 5 5 0.3295078
#> 6 6 -0.8204684
编辑:添加了 2014-18 年的输出。
这里有一个函数可以帮助解决这个问题。输入年份和 day_num(对于那一年),它会输出该日期的标准值。我假设您希望闰年的 4 月 1 日输出标准年的 4 月 1 日,这需要从第 92 天(闰年)转移到 365 天年中的第 91 天。
daily_value <- function(year, day_num) {
leap <- year %in% c(2008, 2012, 2016, 2020, 2024)
leap_day_val <- 0.5 * (mydata[59,2] + mydata[60,2])
day_num_adj <- day_num + ifelse(leap & day_num >= 61, -1, 0)
day_value <- ifelse(leap & day_num == 60,
leap_day_val,
mydata[day_num_adj,2])
day_value
}
测试
mydata[59,]
# myday myvalue
#59 59 0.5697196
daily_value(2016,59)
#[1] 0.5697196
mydata[59:60,]
# myday myvalue
#59 59 0.5697196
#60 60 -0.1350546
mean(c(0.5697196, -0.1350546))
#[1] 0.2173325
daily_value(2016,60)
#[1] 0.2173325
# Day 61 of 2016 was March 1, which is day 60 in years with 365 days
mydata[60,]
# myday myvalue
#60 60 -0.1350546
daily_value(2016,61)
#[1] -0.1350546
现在,我们可以将其应用于 2014-18 年的所有日子:
output <- data.frame(dates = seq.Date(as.Date("2014-01-01"), as.Date("2018-12-31"), 1))
output$day_of_year = lubridate::yday(output$dates)
output$value = daily_value(lubridate::year(output$dates), output$day_of_year)
subset(output, day_of_year > 58 & day_of_year <= 61)
# dates day_of_year value
#59 2014-02-28 59 0.5697196
#60 2014-03-01 60 -0.1350546
#61 2014-03-02 61 2.4016178
#424 2015-02-28 59 0.5697196
#425 2015-03-01 60 -0.1350546
#426 2015-03-02 61 2.4016178
#789 2016-02-28 59 0.5697196
#790 2016-02-29 60 0.2173325 # Leap day gets avg of 2/28 and 3/01
#791 2016-03-01 61 -0.1350546 # Rest of leap year shifted back one day
#1155 2017-02-28 59 0.5697196
#1156 2017-03-01 60 -0.1350546
#1157 2017-03-02 61 2.4016178
#1520 2018-02-28 59 0.5697196
#1521 2018-03-01 60 -0.1350546
#1522 2018-03-02 61 2.4016178
您可以使用 lubridate
中的 leap_year
函数。我已经编写了两个函数来自动执行您的任务:
set.seed(1)
mydata <- rnorm(365)
generate_days <- function(years){
unlist(sapply(years, function(x) {
if (lubridate::leap_year(x)){
1:366} else {
1:365}
}))
}
generate_data <- function(years, my_data){
unlist(sapply(years, function(x) {
if (lubridate::leap_year(x)){
c(my_data[1:59], mean(my_data[59:60]), my_data[60:365])} else {
my_data}
}))
}
df <- data.frame(days = generate_days(2014:2018),
value = generate_data(2014:2018, mydata))
df[730+60,]