对连续日期进行分组 [重复问题,但无法使其与我的数据一起使用]

Group consecutive dates [duplicate question, but can't make it work with my data]

我有一个包含 142 列的数据库,其中一列称为“日期”(属于 class POSIXct),我想从这些连续日期组中创建一个新列。彼此相隔超过 2 天的日期将被分为不同的组。

我还想用连续日期开始的月份名称来命名组级别(例如:2018 年 1 月 3 日 -> 2018 年 1 月 12 日 = 组级别称为“一月采样事件” ";2018 年 2 月 27 日 -> 2018 年 3 月 1 日 = 组级别称为“二月采样事件”;等等...)。

我见过非常相似的问题,例如 and ,但无法让它对我的数据起作用。

编辑: 我的数据示例(最后一行显示分隔超过一年的日期出于某种原因被分组在一起)

    > dput(df)
structure(list(Date = structure(c(17534, 17535, 17536, 17537, 
18279, 18280, 18281, 18282, 17932), class = "Date"), group = c(1, 
1, 1, 1, 2, 2, 2, 2, 2)), row.names = c(NA, -9L), class = c("tbl_df", 
"tbl", "data.frame"))

我的尝试:

df$group <- 1 + c(0, cumsum(ifelse(diff(df$Date) > 1, 1, 0)))

从日期时间中删除时间

如果没有看到您的数据(或类似的示例数据),很难准确判断问题出在哪里,但我的猜测是日期时间格式(00:00:00 部分)搞砸了 as.Date

一个解决方案是只提取日期部分,然后只用日期部分重试:

# here are your date times
date_time <- "2018-01-03 00:00:00"

# this looks for 4 digits between 0 and 9, followed by a dash, followed by 2 digits between 0 and 9,followed by a dash, followed by 2 digits between 0 and 9  
date_pattern <- " ?([0-9]{4}-[0-9]{2}-[0-9]{2}) ?"

#need this library
library(stringr)
library(magrittr) #for pipes

#this pulls out text matching the pattern we specified in date pattern
date_new <- str_extract(date_time, date_pattern) %>% 
  str_squish()   # this removes white space

# this is the new date without the time
date_new

# then we convert to as date
date_new <- as.Date(date_new)

查看是否将日期列转换为日期,然后重新运行分组。

如果您有不同格式的日期并且需要调整正则表达式,这里有一些关于正则表达式的内容:

团体日期

让我们从包含日期列的示例数据框开始

# here's a bunch of example dates:
library(lubridate)
dates2 <- seq.Date(as.Date("2018-03-01"),by="days",length.out = 60)

#here's the dataframe
exampl_df <- data.frame(animals = rep(c("cats","dogs","rabbits"),20), dates=dates2,
                        numbers= rep(1:3,20))

这是它的样子:

head(exampl_df)
  animals      dates numbers
1    cats 2018-03-01       1
2    dogs 2018-03-02       2
3 rabbits 2018-03-03       3
4    cats 2018-03-04       1
5    dogs 2018-03-05       2
6 rabbits 2018-03-06       3

然后让我们在序列中的最小日期和最大日期之间制作一个每天的序列。这一步很重要,因为我们的数据中可能缺少日期,我们仍然希望将这些日期计入天数之间的间隔。

# this is a day by day sequence from the earliest day in your data to the latest day
date_sequence <- seq.Date(from = min(dates2),max(dates2),by="day")

然后让我们制作一个数字序列,每个数字重复七次。如果你想每三天分组,你可以将每个更改为 3。然后 length.out= length(date_sequence) 告诉 R 使这个向量具有与最小到最大日期序列一样多的条目:

# and then if you want a new group every seven days you can make this number sequence
groups <- rep(1:length(date_sequence),each= 7, length.out = length(date_sequence) )

然后让我们将组附加到 date_sequence 以创建分组索引

date_grouping_index <- data.frame(a=date_sequence,b=groups)

然后您可以进行连接以将组附加到原始数据框

library(dplyr)
example_df 2 <- exampl_df %>% 
  inner_join(date_grouping_index, by=c("dates"="a"))

这是我们得到的:

head(example_df2,n=10)
   animals      dates numbers b
1     cats 2018-03-01       1 1
2     dogs 2018-03-02       2 1
3  rabbits 2018-03-03       3 1
4     cats 2018-03-04       1 1
5     dogs 2018-03-05       2 1
6  rabbits 2018-03-06       3 1
7     cats 2018-03-07       1 1
8     dogs 2018-03-08       2 2
9  rabbits 2018-03-09       3 2
10    cats 2018-03-10       1 2

那么您应该能够 group_by()aggregate() 您的数据使用列 b

使用问题中提供的数据

#original data
df <- structure(list(Date = structure(c(17534, 17535, 17536, 17537, 
                                        18279, 18280, 18281, 18282, 17932), class = "Date"), group = c(1, 
                                                                                                     1, 1, 1, 2, 2, 2, 2, 2)), row.names = c(NA, -9L), class = c("tbl_df", 
                                                                                                                                                                   "tbl", "data.frame"))

#plus extra step
df$group2 <- 1 + c(0, cumsum(ifelse(diff(df$Date) > 1, 1, 0)))

上述方法

date_sequence <- seq.Date(from = min(df$Date),max(df$Date),by="day")
groups <- rep(1:length(date_sequence),each= 7, length.out = length(date_sequence) )
date_grouping_index <- data.frame(a=date_sequence,groups=groups)

example_df2<- df %>% 
  inner_join(date_grouping_index, by=c("Date"="a"))

看起来有效?

example_df2
# A tibble: 9 x 4
  Date       group group2 groups
  <date>     <dbl>  <dbl>  <int>
1 2018-01-03     1      1      1
2 2018-01-04     1      1      1
3 2018-01-05     1      1      1
4 2018-01-06     1      1      1
5 2020-01-18     2      2    107
6 2020-01-19     2      2    107
7 2020-01-20     2      2    107
8 2020-01-21     2      2    107
9 2019-02-05     2      2     57

您可以执行以下操作来创建包含日期和年份的群组名称:

example_df2$group_name <- paste0("sampling number ",
                                example_df2$groups,
                                " (",
                                month.name[month(example_df2$Date)],
                                "-",
                                year(example_df2$Date),
                                ")")