r - 在 R 中对连续日期进行分组

标签 r date grouping

我正在寻找一个 R 包来将连续的日期分组为句点。此外,列必须按 FID、PID 和 SETTING 分组:

# Input data
input <- read.csv(text=
    "FID,PID,SETTING,DATE
    00001, 100001, ST, 2021-01-01
    00001, 100001, ST, 2021-01-02
    00001, 100001, ST, 2021-01-03
    00001, 100002, AB, 2021-01-04
    00001, 100001, ST, 2021-01-11
    00001, 100001, ST, 2021-01-12
    00002, 200001, AB, 2021-01-02
    00002, 200001, AB, 2021-01-03
    00002, 200001, AB, 2021-01-04
    00002, 200002, TK, 2021-01-05"
)

# Expected output
output <- read.csv(text="
    FID,PID,SETTING,START,END
    00001, 100001, ST, 2021-01-01, 2021-01-03
    00001, 100002, AB, 2021-01-04, 2021-01-04
    00001, 100001, ST, 2021-01-11, 2021-01-12
    00002, 200001, AB, 2021-01-02, 2021-01-04
    00002, 200002, TK, 2021-01-05, 2021-01-05"
)

我要对大约 700'000 行进行分组。因此,解决方案应尽可能高效。

最佳答案

碱基R

input <- input[order(input$DATE),]
input$grp <- ave(as.integer(input$DATE), input[-4], FUN = function(z) cumsum(c(TRUE, diff(z) > 1)))
input
#    FID    PID SETTING       DATE grp
# 1    1 100001      ST 2021-01-01   1
# 2    1 100001      ST 2021-01-02   1
# 7    2 200001      AB 2021-01-02   1
# 3    1 100001      ST 2021-01-03   1
# 8    2 200001      AB 2021-01-03   1
# 4    1 100002      AB 2021-01-04   1
# 9    2 200001      AB 2021-01-04   1
# 10   2 200002      TK 2021-01-05   1
# 5    1 100001      ST 2021-01-11   1
# 6    1 100001      ST 2021-01-12   1

out <- aggregate(DATE ~ FID + PID + SETTING + grp, data = input,
                 FUN = function(z) setNames(range(z), c("START","END")))
out <- do.call(data.frame, out)
out[,5:6] <- lapply(out[,5:6], as.Date, origin = "1970-01-01")
out
#   FID    PID SETTING grp DATE.START   DATE.END
# 1   1 100002      AB   1 2021-01-04 2021-01-04
# 2   2 200001      AB   1 2021-01-02 2021-01-04
# 3   1 100001      ST   1 2021-01-01 2021-01-03
# 4   2 200002      TK   1 2021-01-05 2021-01-05
# 5   1 100001      ST   2 2021-01-11 2021-01-12

演练:

  • cumsumdiff 的易用性是在假设日期总是有序的情况下实现的; (此处)其他分组变量可能顺序不正确并不重要;
  • ave(..) 分配非连续(超过 1 个)日期组,我们将在下一步中使用这些日期;
  • aggregate 使用您的三个变量加上我们新的 grp 分组变量计算每个组内的范围;匿名函数中的每个 z 都是一个连续的日期向量,因此 range 为我们提供了开始/结束日期;
  • 不幸的是,聚合分配了一个矩阵作为第五列而不是两个单独的列,因此do.call(data.frame, out)修复了这个问题;<
  • 不幸的是,大多数基本 R 聚合函数倾向于从向量中剥离 Date(和 POSIXt)类,因此我们需要使用 as.Date 来治愈它。

dplyr

library(dplyr)
input %>%
  arrange(DATE) %>%
  group_by(FID, PID, SETTING) %>%
  mutate(grp = cumsum(c(TRUE, diff(DATE) > 1))) %>%
  group_by(FID, PID, SETTING, grp) %>%
  summarize(START = min(DATE), END = max(DATE)) %>%
  ungroup()
# # A tibble: 5 x 6
#     FID    PID SETTING   grp START      END       
#   <int>  <int> <chr>   <int> <date>     <date>    
# 1     1 100001 " ST"       1 2021-01-01 2021-01-03
# 2     1 100001 " ST"       2 2021-01-11 2021-01-12
# 3     1 100002 " AB"       1 2021-01-04 2021-01-04
# 4     2 200001 " AB"       1 2021-01-02 2021-01-04
# 5     2 200002 " TK"       1 2021-01-05 2021-01-05

数据表

library(data.table)
inputDT <- as.data.table(input)
setorder(inputDT, DATE)
inputDT[, grp := cumsum(c(TRUE, diff(DATE) > 1)), by = .(FID, PID, SETTING)
  ][, .(START = min(DATE), END = max(DATE)), by = .(FID, PID, SETTING, grp)
  ][]
#      FID    PID SETTING   grp      START        END
#    <int>  <int>  <char> <int>     <Date>     <Date>
# 1:     1 100001      ST     1 2021-01-01 2021-01-03
# 2:     2 200001      AB     1 2021-01-02 2021-01-04
# 3:     1 100002      AB     1 2021-01-04 2021-01-04
# 4:     2 200002      TK     1 2021-01-05 2021-01-05
# 5:     1 100001      ST     2 2021-01-11 2021-01-12

关于r - 在 R 中对连续日期进行分组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69676186/

相关文章:

R ggplot2 为组均值绘制条形图

PHP DateTime - 从 YEAR、WEEK 和 WEEKDAY 生成

.net - 一种对加权对象列表进行排序和分组的算法

list - 获取 xsl 1.0 仅显示列表中组中的第一项

ruby - 根据第一个元素对数组进行分组,在 Ruby 中没有重复

R 在图本身上打印线性回归方程

r - 并行进程的共享内存

R - Shiny 找不到 "container"

mysql - 将日期转换为配置单元中的时间戳

windows - 如何编写 Windows 批处理脚本以将最新文件从目录复制到新文件夹?