【问题标题】:Creating intervals创建间隔
【发布时间】:2021-07-03 00:38:30
【问题描述】:

我有一个数据集,我想分成 10 天的时间间隔。我在下面包含的代码可以做到这一点,但是在过去一周左右的时间里,有些日子(例如,一个月的 31 日或 30 日)仍然会自行结束。

我想删除创建它的间隔或将它们包含在以前的间隔中。

例如: 如果我将 1 月份以 10 天为间隔,它会将前 10 天放在列表的一个元素中,第二个 10 天放在另一个元素中,第三个 10 天放在另一个元素中。然后它会将 1 月 31 日单独放入列表元素中。

我想要的输出是要么从列表中删除这些元素,要么最好将它们包含在第三个 10 天间隔中。可以这样做吗?如果是这样,最好的方法是什么?

library(lubridate)
library(tidyverse)
date <- rep_len(seq(dmy("26-12-2010"), dmy("20-12-2013"), by = "days"), 500)
ID <- rep(seq(1, 5), 100)

df <- data.frame(date = date,
                 x = runif(length(date), min = 60000, max = 80000),
                 y = runif(length(date), min = 800000, max = 900000),
                 ID)

int <- df %>%
  arrange(ID) %>% 
  mutate(new = ceiling_date(date, '10 day')) %>% 
  # mutate(cut = data.table::rleid(cut(new, breaks = "10 day"))) %>% 
  group_by(new) %>%
  group_split()

【问题讨论】:

    标签: r tidyverse lubridate


    【解决方案1】:

    这是一个解决方案,它以 10 天为间隔分割月份,但更正 new 以将一个月的第 31 天分配给最后一个时期。所以,

    • 第 1 天到第 10 天属于一个月的前三分之一,
    • 第 11 天到第 20 天到第二个三分之一,以及
    • 第 21 天到第 31 天到第三天。
    int <- df %>%
      # arrange(ID) %>%   # skipped for readability of result
      mutate(new = floor_date(date, '10 day')) %>%
      mutate(new = if_else(day(new) == 31, new - days(10), new)) %>% 
      group_by(new) %>%
      group_split()
    
    int[[1]]
    
    # A tibble: 6 x 5
      date            x       y    ID new       
      <date>      <dbl>   <dbl> <int> <date>    
    1 2010-12-26 71469. 819084.     1 2010-12-21
    2 2010-12-27 69417. 893227.     2 2010-12-21
    3 2010-12-28 70865. 831341.     3 2010-12-21
    4 2010-12-29 68322. 812423.     4 2010-12-21
    5 2010-12-30 65643. 837395.     5 2010-12-21
    6 2010-12-31 63638. 892200.     1 2010-12-21
    

    现在,2010-12-31 被分配到 12 月 3 日。

    注意new 通过调用floor_date() 而不是ceiling_date() 表示间隔的开始。这是为了避免跨月边界的日算术的潜在问题,并澄清间隔属于哪个月。例如,对于二月的最后一天,ceiling_date(ymd('2011-02-28'), '10 day') 返回“2011-03-03”,即三月的日期。

    【讨论】:

      【解决方案2】:

      如果组中只有一行,则为其赋予之前的new 值。试试这个 -

      library(dplyr)
      library(lubridate)
      
      df %>%
        arrange(ID, date) %>% 
        mutate(new = ceiling_date(date, '10 day')) %>%
        add_count(new) %>%
        mutate(new = if_else(n == 1, lag(new), new)) %>%
        select(-n) %>%
        group_split(new)
      

      以上方法仅适用于组合在一个组中具有 1 个观察值的组。如果我们想组合超过 1 天,请使用下面的代码来计算组中的天数。如果天数小于n 天数,则合并组。

      n <- 2
      
      df %>%
        arrange(ID, date) %>% 
        mutate(new = ceiling_date(date, '10 day'), 
               ID = match(new, unique(new))) -> tmp
      tmp %>%
        group_by(new, ID) %>%
        summarise(count_unique = n_distinct(date)) %>%
        ungroup %>%
        mutate(new = if_else(count_unique < n, lag(new), new)) %>%
        inner_join(tmp, by = 'ID') %>%
        select(new = new.x, date, x, y) %>%
        group_split(new)
      

      【讨论】:

      • 如果组中有多个我想删除的观察,我将如何修改它?我可以将 1 更改为其他内容吗?在我的实际数据集中,不同组的观察次数有所不同。
      • 这种方法仅适用于组中的 1 行。对于超过 1 天,您可以使用我更新的答案。 @JohnHuang
      【解决方案3】:

      替代解决方案

      library(lubridate)
      library(tidyverse)
      
      dt <- rep_len(seq(dmy("26-12-2010"), dmy("20-12-2013"), by = "days"), 500)
      ID <- rep(seq(1, 5), 100)
      
      df <- data.frame(dt = dt,
        x = runif(length(dt), min = 60000, max = 80000),
        y = runif(length(dt), min = 800000, max = 900000),
        ID)
      
      1. 将额外天数(第 31 天)添加到最后三分之一
      int_df <- df %>%
        # arrange(ID) %>%
        mutate(day_date = day(dt),
          day_new = case_when(
            day_date <= 10  ~ 1,
            day_date <= 20  ~ 11,
            TRUE            ~ 21
          ),
          new = ymd(paste(year(dt), month(dt), day_new, sep = "-"))) %>% 
        select(-c(day_date, day_new)) %>% 
        group_by(new) %>%
        group_split()
      
      int_df[[1]]
      #> # A tibble: 6 x 5
      #>   dt              x       y    ID new       
      #>   <date>      <dbl>   <dbl> <int> <date>    
      #> 1 2010-12-26 62395. 837491.     1 2010-12-21
      #> 2 2010-12-27 66236. 836481.     2 2010-12-21
      #> 3 2010-12-28 79918. 818399.     3 2010-12-21
      #> 4 2010-12-29 67613. 807213.     4 2010-12-21
      #> 5 2010-12-30 72980. 899380.     5 2010-12-21
      #> 6 2010-12-31 61004. 876191.     1 2010-12-21
      
      1. 不包括额外天数(第 31 天)
      int_df <- df %>%
        # arrange(ID) %>%
        mutate(day_date = day(dt),
          day_new = case_when(
            day_date <= 10  ~ 1,
            day_date <= 20  ~ 11,
            day_date <= 30  ~ 21,
            TRUE            ~ 31
          ),
          new = ymd(paste(year(dt), month(dt), day_new, sep = "-"))) %>% 
        filter(day_date != 31) %>% 
        select(-c(day_date, day_new)) %>%
        group_by(new) %>%
        group_split()
      
      int_df[[1]]
      #> # A tibble: 5 x 5
      #>   dt              x       y    ID new       
      #>   <date>      <dbl>   <dbl> <int> <date>    
      #> 1 2010-12-26 62395. 837491.     1 2010-12-21
      #> 2 2010-12-27 66236. 836481.     2 2010-12-21
      #> 3 2010-12-28 79918. 818399.     3 2010-12-21
      #> 4 2010-12-29 67613. 807213.     4 2010-12-21
      #> 5 2010-12-30 72980. 899380.     5 2010-12-21
      

      reprex package (v2.0.0) 于 2021 年 7 月 3 日创建

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-02-08
        • 1970-01-01
        • 2015-08-31
        • 2023-04-02
        相关资源
        最近更新 更多