【问题标题】:R: assign seasons to dates by day and monthR:按日和月将季节分配给日期
【发布时间】:2020-11-03 15:54:47
【问题描述】:

我有一个数据框,其中包含多年的日期。看起来像这样(而不是三年,我有 40 年):

DATES<-c(seq(as.Date('2017-01-01'), as.Date('2019-12-31'), by = 'days'))
df<-data.frame(DATES)

对于我想添加季节的每一天。因此,春季应从 3 月 20 日开始,夏季从 6 月 21 日开始,秋季从 9 月 23 日开始,冬季从 12 月 21 日开始。这些日期多年来保持不变。

我想出了以下代码,它有效(至少,我认为是这样)。但是,我想知道,如果没有更优雅的方式来获得我想要的东西。

df$MONTH<-month(df$DATES)
df$DAY<-mday(df$DATES)
df$DAY_PLUS_MONTH<-df$DAY+df$MONTH*100

df <- df %>%
  mutate(SEASON = case_when(
    DAY_PLUS_MONTH %in% 320:620 ~ 'SPRING',
    DAY_PLUS_MONTH %in% 621:922 ~ 'SUMMER',
    DAY_PLUS_MONTH %in% 923:1221 ~ 'AUTUMN',
    TRUE ~ 'WINTER'))

【问题讨论】:

  • 这个问题有一堆解决方案here

标签: r


【解决方案1】:

我认为这应该适合你:

cut(lubridate::yday(df$DATES - lubridate::days(79)), 
    breaks = c(0, 93, 187, 276, Inf), 
    labels = c("Spring", "Summer", "Autumn", "Winter"))

【讨论】:

  • 我正要建议同样的事情,使用as.POSIXlt(.)$yday。但是……这在闰年不是有点不同吗?
  • @r2evans 是的,我确实考虑过这一点:我想我的想法是日期限制有点武断 - 在闰年时植物在生长前等待额外的一天真是令人惊讶:)。 .. 或者也许是额外的简单性弥补了轻微的不准确,或者我什至可能有点懒惰......无论如何 - 你做得好得到 +1!
  • 自从我开始与在处理记录时间序列数据流时不了解(例如)TZ 重要性的合作伙伴合作以来,我就成了一个极端案例迷。它工作得很好,直到它没有。这当然更具可读性,如果用户愿意接受一般性(和罕见的不一致),那么可读性通常胜过精确度。
【解决方案2】:

使用$yday(无论是来自lubridate 还是as.POSIXlt)可能会给出闰年的错误结果。我认为更安全的方法是为这些年份中的每个日期创建一个向量,在每个方向(之前/之后)添加一年。

我正在使用findInterval,但它与cut 非常接近,您可以在此处使用相同的变量来使用该方法。

season_dates <- as.Date(sort(c(outer(
  do.call(seq.int, as.list(1900 + as.POSIXlt(range(df$DATES) + c(-365, 365))$year)), 
  c("-03-20", "-06-21", "-09-23", "-12-21"),
  paste0))))
season_dates
#  [1] "2016-03-20" "2016-06-21" "2016-09-23" "2016-12-21" "2017-03-20" "2017-06-21" "2017-09-23" "2017-12-21" "2018-03-20"
# [10] "2018-06-21" "2018-09-23" "2018-12-21" "2019-03-20" "2019-06-21" "2019-09-23" "2019-12-21" "2020-03-20" "2020-06-21"
# [19] "2020-09-23" "2020-12-21"
season_names <- rep(c("Spring", "Summer", "Autumn", "Winter"), length.out = length(season_dates))
season_names
#  [1] "Spring" "Summer" "Autumn" "Winter" "Spring" "Summer" "Autumn" "Winter" "Spring" "Summer" "Autumn" "Winter" "Spring"
# [14] "Summer" "Autumn" "Winter" "Spring" "Summer" "Autumn" "Winter"

set.seed(42)
as_tibble(df) %>%
  mutate(SEASON = season_names[ findInterval(DATES, season_dates) ]) %>%
  sample_n(10) %>%
  arrange(DATES)
# # A tibble: 10 x 2
#    DATES      SEASON
#    <date>     <chr> 
#  1 2017-01-24 Winter
#  2 2017-02-18 Winter
#  3 2017-06-14 Spring
#  4 2017-11-17 Autumn
#  5 2017-12-22 Winter
#  6 2018-02-14 Winter
#  7 2018-07-15 Summer
#  8 2018-09-14 Summer
#  9 2018-09-26 Autumn
# 10 2019-06-18 Spring

我对输出进行采样只是为了显示一些差异,否则前 10 个结果都是冬天的。另外,我使用了as.POSIXlt(.)$year,然后不得不对其进行调整,因为它是基于 1900 的。 lubridate::year 也可以在这里工作。

【讨论】:

  • 谢谢!你能向我解释一下,set.seed(42) 是干什么用的?
  • 只是因为我在显示中使用了随机性。如果我没有提供,而你使用了sample_n(10),你会得到不同的结果。通过包含set.seed(42),您应该会看到相同的随机抽样显示。但是,对于常规使用,既不需要 set.seed 也不需要 sample_n
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-22
  • 1970-01-01
相关资源
最近更新 更多