【问题标题】:Fill in gaps between irregular end and start timestamps填补不规则结束和开始时间戳之间的空白
【发布时间】:2022-12-03 12:15:57
【问题描述】:

我正在 Shiny 开发一个简单的时间表/时间跟踪应用程序供个人使用。该应用程序将记录我开始和停止活动的时间戳。但是,一天中的某些时候,特定任务之间存在自然间隙,您仍然需要做一些事情。这些中间时间段不会被应用程序捕获,但会作为时间戳之间的“间隙”出现在数据中。示例数据如下所示(帖子末尾的数据输出):

# A tibble: 9 x 3
  start               end                 activity  
  <dttm>              <dttm>              <chr>     
1 2022-11-28 10:00:00 2022-11-28 10:50:30 Activity 1
2 2022-11-28 10:50:30 2022-11-28 11:39:05 Activity 2
3 2022-11-28 12:01:00 2022-11-28 16:10:45 Activity 2
4 2022-11-29 10:00:00 2022-11-29 10:50:30 Activity 1
5 2022-11-29 10:50:31 2022-11-29 11:00:15 Activity 4
6 2022-11-29 12:00:00 2022-11-29 13:00:00 Activity 5
7 2022-11-29 13:00:00 2022-11-29 16:00:00 Activity 2
8 2022-11-30 08:00:05 2022-11-30 10:00:00 Activity 1
9 2022-11-30 16:03:05 2022-11-30 17:00:00 Activity 2

数据的差距是显而易见的。例如,在 28 日,第一个条目和第二个条目之间没有间隔(第一个条目的结束时间等于第二个条目的开始时间)。但是,第二个条目和第三个条目之间存在间隙(第二个条目的结束时间与第三个条目不同)。我们可以在样本数据中找到其他日子的类似差距。

我想做的是用一个名为“其他”的活动来填补这些空白,这样每天第一个条目的开始和最后一个条目的结束之间就没有间隙。也就是说,所有现有的差距都被填补了。所需的输出将如下所示:

# A tibble: 13 x 3
   start               end                 activity  
   <dttm>              <dttm>              <chr>     
 1 2022-11-28 10:00:00 2022-11-28 10:50:30 Activity 1
 2 2022-11-28 10:50:30 2022-11-28 11:39:05 Activity 2
 3 2022-11-28 11:39:05 2022-11-28 12:01:00 Other     
 4 2022-11-28 12:01:00 2022-11-28 16:10:45 Activity 2
 5 2022-11-29 10:00:00 2022-11-29 10:50:30 Activity 1
 6 2022-11-29 10:50:30 2022-11-29 10:50:31 Other     
 7 2022-11-29 10:50:31 2022-11-29 11:00:15 Activity 4
 8 2022-11-29 11:00:15 2022-11-29 12:00:00 Other     
 9 2022-11-29 12:00:00 2022-11-29 13:00:00 Activity 5
10 2022-11-29 13:00:00 2022-11-29 16:00:00 Activity 2
11 2022-11-30 08:00:05 2022-11-30 10:00:00 Activity 1
12 2022-11-30 10:00:00 2022-11-30 16:03:05 Other     
13 2022-11-30 16:03:05 2022-11-30 17:00:00 Activity 2

在可预见的未来,数据将每天创建,因此该解决方案可能必须在更大的数据集上运行,并且矢量化方法更可取。到目前为止,我一直在 tidyverse 和 lubridate 工作。我不确定我是否忽略了一些简单/容易的事情(我希望如此)。

我首先想到的是写一个循环或者使用 lapply 类型的表达式。随着数据的增长,这可能会很快失控,除非我记得始终填写或运行检查并定期填写数据(我最终可能会到达应用程序的这一部分)。

或者,我开始考虑将数据旋转更长的时间,创建每组 2 场比赛,每天都有开始和结束时间,以找出差距。这可能很快,但我很难找到解决问题的好方法。

如果重要,每次添加条目时,数据都会提交到本地 SQLite 数据库。

非常感谢对此的任何帮助/输入。

样本数据:

library(tidyverse)
library(lubridate)

db <- structure(list(start = structure(c(1669629600, 1669632630, 1669636860, 
1669716000, 1669719031, 1669723200, 1669726800, 1669795205, 1669824185
), class = c("POSIXct", "POSIXt"), tzone = "UTC"), end = structure(c(1669632630, 
1669635545, 1669651845, 1669719030, 1669719615, 1669726800, 1669737600, 
1669802400, 1669827600), class = c("POSIXct", "POSIXt"), tzone = "UTC"), 
    activity = c("Activity 1", "Activity 2", "Activity 2", "Activity 1", 
    "Activity 4", "Activity 5", "Activity 2", "Activity 1", "Activity 2"
    )), row.names = c(NA, -9L), class = c("tbl_df", "tbl", "data.frame"
))

【问题讨论】:

    标签: r tidyverse lubridate


    【解决方案1】:

    这是一种方法:

    library(dplyr)
    library(lubridate)
    
    db %>% 
      bind_rows(
        data.frame(
          start = db %>% 
            group_by(day(start)) %>% 
            filter(end != lead(start)) %>% 
            pull(end),
          end = NA,
          activity= "Other"
        )
      ) %>% 
      arrange(start) %>% 
      mutate(end = if_else(is.na(end),lead(start),end))
    
    # A tibble: 13 x 3
       start               end                 activity  
       <dttm>              <dttm>              <chr>     
     1 2022-11-28 10:00:00 2022-11-28 10:50:30 Activity 1
     2 2022-11-28 10:50:30 2022-11-28 11:39:05 Activity 2
     3 2022-11-28 11:39:05 2022-11-28 12:01:00 Other     
     4 2022-11-28 12:01:00 2022-11-28 16:10:45 Activity 2
     5 2022-11-29 10:00:00 2022-11-29 10:50:30 Activity 1
     6 2022-11-29 10:50:30 2022-11-29 10:50:31 Other     
     7 2022-11-29 10:50:31 2022-11-29 11:00:15 Activity 4
     8 2022-11-29 11:00:15 2022-11-29 12:00:00 Other     
     9 2022-11-29 12:00:00 2022-11-29 13:00:00 Activity 5
    10 2022-11-29 13:00:00 2022-11-29 16:00:00 Activity 2
    11 2022-11-30 08:00:05 2022-11-30 10:00:00 Activity 1
    12 2022-11-30 10:00:00 2022-11-30 16:03:05 Other     
    13 2022-11-30 16:03:05 2022-11-30 17:00:00 Activity 2
    

    【讨论】:

      【解决方案2】:

      这是另一种使用 tidyverse 的方法。添加一列以指示下一行 start 时间。然后,筛选出有间隙的行(end时间小于下一行start时间)。将这些行更改为“其他”并修改间隔时间。然后,使用 bind_rows 添加回原始 data.frame。

      library(tidyverse)
      library(lubridate)
      
      db %>%
        group_by(day(start)) %>%
        mutate(nextstart = lead(start)) %>%
        ungroup() %>%
        filter(end < nextstart) %>%
        transmute(start = end, end = nextstart, activity = "Other") %>%
        bind_rows(db) %>%
        arrange(start)
      

      输出

         start               end                 activity  
         <dttm>              <dttm>              <chr>     
       1 2022-11-28 10:00:00 2022-11-28 10:50:30 Activity 1
       2 2022-11-28 10:50:30 2022-11-28 11:39:05 Activity 2
       3 2022-11-28 11:39:05 2022-11-28 12:01:00 Other     
       4 2022-11-28 12:01:00 2022-11-28 16:10:45 Activity 2
       5 2022-11-29 10:00:00 2022-11-29 10:50:30 Activity 1
       6 2022-11-29 10:50:30 2022-11-29 10:50:31 Other     
       7 2022-11-29 10:50:31 2022-11-29 11:00:15 Activity 4
       8 2022-11-29 11:00:15 2022-11-29 12:00:00 Other     
       9 2022-11-29 12:00:00 2022-11-29 13:00:00 Activity 5
      10 2022-11-29 13:00:00 2022-11-29 16:00:00 Activity 2
      11 2022-11-30 08:00:05 2022-11-30 10:00:00 Activity 1
      12 2022-11-30 10:00:00 2022-11-30 16:03:05 Other     
      13 2022-11-30 16:03:05 2022-11-30 17:00:00 Activity 2
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-01-12
        • 1970-01-01
        • 2018-07-13
        • 1970-01-01
        • 1970-01-01
        • 2021-01-26
        相关资源
        最近更新 更多