繁体   English   中英

r 多年的日期范围子集数据集

[英]r subset dataset by date range over multiple years

我正在处理一个多年数据集,该数据集包含日期列 (%Y-%m-%d) 和多个变量的每日值。
在 R 中,如何按日期范围(即 6 月 29 日 +/- 5 天)对数据进行子集化,但捕获所有年份的数据?

               DATE        A       B      C
1996-06-10 12:00:00    178.0    24.1    1.7

1996-06-11 12:00:00    184.1    30.2    1.1

1996-06-12 12:00:00    187.2    29.4    1.8

1996-06-13 12:00:00    194.4    35.0    5.3

1996-06-14 12:00:00    200.3    35.9    1.5

1996-06-15 12:00:00    138.9    15.1    0.0

...

1)基础R

假设yrs是数据中所有唯一的年份,而targets是具有目标月份和日期的每个年份。 然后创建dates ,其中包含targets中任何值的delta天之内的所有日期。 请注意, sapply"Date"类的dates ,但这并不重要,因为它仅随后用于%in%并且会忽略该类。 最后,将DF子集向下到DATEdates那些行。 不使用任何软件包。

# inputs (also DF defined in Note at end)
target <- "06-19"
delta <- 5

DATE <- as.Date(DF$DATE)
yrs <- unique(format(DATE, "%Y"))
targets <- as.Date(paste(yrs, target, sep = "-"))
dates <- c(sapply(targets, "+", seq(-delta, delta)))
DF[DATE %in% dates, ]

赠送:

                 DATE     A    B   C
5 1996-06-14 12:00:00 200.3 35.9 1.5
6 1996-06-15 12:00:00 138.9 15.1 0.0

2)sqldf

或者,可以使用单个SQL语句完成此操作。 请注意,我们假设DATE列是字符,因为提到的问题采用特定格式。 现在,内部选择使用相同的输入来生成每年的目标日期,然后外部选择将DF与任何目标日期delta几天内的行连接起来。 我们在这里使用H2数据库后端,因为它比SQLite具有更好的日期支持。

library(sqldf)
library(RH2) 

# inputs (also DF defined in Note at end)
target <- "06-19"
delta <- 5

fn$sqldf("select DF.* from DF
  join (select distinct cast(substr(DATE, 1, 4) || '-' || '$target' as DATE) as target 
        from DF) 
    on cast(substr(DATE, 1, 10) as DATE) between target - $delta and target + $delta")

赠送:

                 DATE     A    B   C
1 1996-06-14 12:00:00 200.3 35.9 1.5
2 1996-06-15 12:00:00 138.9 15.1 0.0

如果DATE是R的"Date"类,则可以稍微简化SQL。 也就是说,将上面的sqldf语句替换为:

DF2 <- transform(DF, DATE = as.Date(DATE))
fn$sqldf("select DF2.* from DF2
  join (select distinct cast(year(DATE) || '-' || '$target' as DATE) as target from DF2) 
    on DATE between target - $delta and target + $delta")

赠送:

        DATE     A    B   C
1 1996-06-14 200.3 35.9 1.5
2 1996-06-15 138.9 15.1 0.0

注意

假定输入DF为:

DF <- structure(list(DATE = c("1996-06-10 12:00:00", "1996-06-11 12:00:00", 
"1996-06-12 12:00:00", "1996-06-13 12:00:00", "1996-06-14 12:00:00", 
"1996-06-15 12:00:00"), A = c(178, 184.1, 187.2, 194.4, 200.3, 
138.9), B = c(24.1, 30.2, 29.4, 35, 35.9, 15.1), C = c(1.7, 1.1, 
1.8, 5.3, 1.5, 0)), .Names = c("DATE", "A", "B", "C"), row.names = c(NA, 
-6L), class = "data.frame")

基本R尝试。

窃取来自Kevin另一个答案的示例数据:

df <- data.frame(
  my_date = seq.Date(as.Date("1990-01-01"), as.Date("1999-12-31"), by = 1),
  x = rnorm(3652),
  y = rnorm(3652),
  z = rnorm(3652)
)

为选择设置变量:

month_num <- 6
day_num <- 29
bound <- 5

查找您年份范围内的关键日期:

keydates <- as.Date(sprintf(
  "%d-%02d-%02d", 
  do.call(seq, as.list(as.numeric(range(format(df$my_date, "%Y"))))),
  month_num,
  day_num
))

进行选择:

out <- df[df$my_date %in% outer(keydates, -bound:bound, `+`),]

检查它是否有效:

table(format(out$my_date, "%m-%d"))
#06-24 06-25 06-26 06-27 06-28 06-29 06-30 07-01 07-02 07-03 07-04 
#   10    10    10    10    10    10    10    10    10    10    10

1990年至1999年期间,每天/每月的一个有效值,以“ 06-29”为中心,每边5天

您可以使用间隔来提供有效的日期范围,然后使用映射在数据上运行每个间隔以进行过滤。

library(dplyr)
library(lubridate)
library(magrittr)  # only because I've used the "exposition" (%$%) pipe
library(purrr)

df <- tibble(
  my_date = as.POSIXct(
    seq.Date(as.Date("1990-01-01"), as.Date("1999-12-31"), by = 1),
    tz = "UTC"
  ),
  x = rnorm(3652),
  y = rnorm(3652),
  z = rnorm(3652)
)

month_num <- 6
day_num <- 29
bound <- 5

date_span <- df %>%
  select(my_date) %>%
  filter(month(my_date) == month_num & day(my_date) == day_num) %>%
  mutate(
    start = my_date - days(bound),
    end = my_date + days(bound)
  ) %$%
  interval(start, end, tzone = "UTC")

map_dfr(date_span, ~filter(df, my_date %within% .x))

# # A tibble: 110 x 4
#    my_date                   x       y       z
#    <dttm>                <dbl>   <dbl>   <dbl>
#  1 1990-06-24 10:00:00  0.404   1.33    1.58  
#  2 1990-06-25 10:00:00  0.351  -1.73    0.665 
#  3 1990-06-26 10:00:00 -0.512   1.01    1.72  
#  4 1990-06-27 10:00:00  1.55    0.417  -0.126 
#  5 1990-06-28 10:00:00  1.86    1.18    0.322 
#  6 1990-06-29 10:00:00 -0.0193 -0.105   0.356 
#  7 1990-06-30 10:00:00  0.844  -0.712   1.51  
#  8 1990-07-01 10:00:00 -0.431   0.451  -2.19  
#  9 1990-07-02 10:00:00  1.74   -0.0650 -0.866 
# 10 1990-07-03 10:00:00  0.965  -0.506  -0.0690
# # ... with 100 more rows

您还可以通过儒略日计算 go,这样您就可以进行基本的算术运算(例如 ± 5 天),而无需在Datecharacter对象之间来回转换。 请记住,您的目标日期在闰年期间会转换为不同的儒略日,因此您需要以某种方式提取这条信息(如果您不喜欢下面的基本 R 方法,请使用lubridate::leap_year ):

## convert dates to julian day
dat$JULDAY = format(
  dat$DATE
  , "%j"
)

## target date (here 19 june) as julian day
dat$TARGET = ifelse(
  as.integer(
    format(
      dat$DATE
      , "%y"
    )
  ) %% 4 == 0
  , 171 # leap year
  , 170 # common year
)

## create subset
subset(
  dat
  , JULDAY >= (TARGET - 5) & JULDAY <= (TARGET + 5)
  , select = c("DATE", "A", "B", "C")
)

#         DATE     A    B   C
# 5 1996-06-14 12:00:00 200.3 35.9 1.5
# 6 1996-06-15 12:00:00 138.9 15.1 0.0

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM