【问题标题】:Select x records after the minimum and max value within factor group(s)在因子组中的最小值和最大值之后选择 x 条记录
【发布时间】:2020-07-21 11:59:02
【问题描述】:

我有一个来自不同地点和不同年份的每日温度数据集。我想选择最小值,然后在该值之后 90 天为每年的每个位置选择记录。我还想选择最大值和 90 天后的记录。抱歉,但鉴于数据的周期性,我不确定如何轻松提供可重现的示例。

例如,如果我想从每年的最低和最高温度后 3 天提取行,则使用以下数据:

date <- c ("1985-01-01", "1985-01-02", "1985-01-03", "1985-01-04", "1985-01-05", "1985-01-06", 
           "1985-01-07", "1985-01-08", "1985-01-09", "1985-01-10", "1985-01-11", "1985-01-12", "1985-01-13", "1985-01-14", "1985-01-15", 
           "1986-01-01", "1986-01-02", "1986-01-03", "1986-01-04", "1986-01-05", "1986-01-06", 
           "1986-01-07", "1986-01-08", "1986-01-09", "1986-01-10", "1986-01-11", "1986-01-12", "1986-01-13", "1986-01-14", "1986-01-15",
           "1987-01-01", "1987-01-02", "1987-01-03", "1987-01-04", "1987-01-05", "1987-01-06", 
           "1987-01-07", "1987-01-08", "1987-01-09", "1987-01-10", "1987-01-11", "1987-01-12", "1987-01-13", "1987-01-14", "1987-01-15")
year <- c(rep(1985, 15), rep(1986, 15), rep(1987, 15))
temp <- c(11, 10, 11, 9, 11, 12, 14, 16, 17, 16, 15, 14, 13, 12, 11, 8, 10, 11, 9, 11, 12, 14, 18, 17, 16, 19, 14, 13, 12, 11,
          11, 10, 11, 9, 11, 7, 14, 16, 17, 16, 15, 18, 17, 12, 11)
df <- as.data.frame(cbind(date, year, temp))

理想情况下,输出将分为两个不同的子集,从每年最低的第一个子集开始:

dflow <- df[c(4:7, 16:19, 36:39), ]   

每年的最高值倒数第二个:

dfhigh <- df[c(9:12, 26:29, 42:45),]

笨拙的例子对不起。与此示例数据和我的真实数据的不同之处在于,真实数据是自 1985 年以来一年中的每一天,我想要在最低和最高温度之后的 90 条记录..

【问题讨论】:

  • 这应该很简单,我的方法是使用data.table non-equi join...但是我无法提供没有可靠示例数据和所需输出的答案...所以请提供那些.

标签: r dplyr data.table tidyverse


【解决方案1】:

这是一个 tidyverse 解决方案。在没有可重复数据的情况下,我编造了一些在 3 年期间遵循周期性模式的数据:

library(dplyr)
library(ggplot2)

set.seed(1)

df <- data.frame(Date = seq(as.Date("2018-01-01"), by = "1 day", length.out = 1096),
                 Temp = 52 - 20 * cos(1:1096 * 2 * pi/365) + rnorm(1096, 0, 5))

请注意,我将所有日期都存储为日期列中的实际日期。从您的数据来看,我会有点担心日期存储为字符串而年份存储为数字。如果是这种情况,最好这样做:

df <- df %>% mutate(Date = strptime(paste(Date, Year), format = "%d-%b %Y"))

在做剩下的事情之前。如果将日期和时间原样存储在数据中,则使用日期和时间会容易得多。

这里的技巧是创建两个新列:post_minpost_max,我们最初将除每年的最低温度和最高温度之外的所有地方都设为零。对于每个向量,我们在取消分组数据后减去其自身的长度为 90 的滞后版本。结果列的cumsum 的最低/最高温度为 1 秒,之后的 90 天为每年。

plot_df <- df %>% 
  mutate(Year = lubridate::year(Date)) %>%
  group_by(Year) %>%
  mutate(post_min = +(Temp == min(Temp)),
         post_max = +(Temp == max(Temp))) %>%
  ungroup() %>%
  mutate(post_min = cumsum(post_min - lag(post_min, 90, default = 0)),
         post_max = cumsum(post_max - lag(post_max, 90, default = 0)))

为了展示这项工作,让我们绘制结果:

  ggplot(plot_df, aes(Date, Temp)) + 
  geom_line() +
  geom_vline(aes(xintercept = Date), plot_df %>% filter(post_min > 0),
             alpha = 0.1, colour = "blue") +
  geom_vline(aes(xintercept = Date), plot_df %>% filter(post_max > 0),
             alpha = 0.1, colour = "red")

你会注意到 2018 年最冷的一天正好发生在年底,所以 90 天跑到 2019 年。2019 年最冷的一天也发生在 12 月,所以它跑到了 2020 年。但是,最冷的一天2020 年是 1 月,因此 2019 年和 2020 年的 90 天重叠。这可能不是您的实际数据的问题,但如果是,您可能希望考虑按例如分组每年 10 月到 10 月。

reprex package (v0.3.0) 于 2020 年 7 月 21 日创建

【讨论】:

  • 实际上,对不起,@Allan Cameron,当我将此代码直接发布到 R 中时,它实际上只标识了每个最小值和最大值的一个句点——而不是图中所示的多个句点。似乎它只是从全局最小值和最大值开始,而不是在每年内。
  • 我很抱歉 - 这是因为我在 dplyr(新秀演习)之后加载了 plyr....
猜你喜欢
  • 1970-01-01
  • 2020-08-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多