如何检查R中两个日期之间的日期?

时间:2019-03-26 02:46:45

标签: r

我有一个看起来像这样的桌子;

user_id     timestamp
aa          2018-01-01 12:01 UTC
ab          2018-01-01 05:01 UTC
bb          2018-06-01 09:01 UTC
bc          2018-03-03 23:01 UTC
cc          2018-01-02 11:01 UTC

我还有另一个桌子,该桌子在2018年每周都有。

week_id    week_start     week_end
1          2018-01-01     2018-01-07
2          2018-01-08     2018-01-15
3          2018-01-16     2018-01-23
4          2018-01-23     2018-01-30
...        ...            ...

假设week_start是星期一,week_end是星期日。

我想做两件事。我首先想将week_id加入到第一个表中,然后再为每个时间戳分配一天。我的输出看起来像这样:

user_id     timestamp               week_id    day_of_week
aa          2018-01-01 12:01 UTC    1          Monday
ab          2018-01-02 05:01 UTC    1          Tuesday
bb          2018-01-13 09:01 UTC    2          Friday
bc          2018-01-28 23:01 UTC    4          Friday
cc          2018-01-06 11:01 UTC    1          Saturday

在Excel中,我可以使用vlookup轻松地做到这一点。我的主要兴趣是学习在这种情况下如何联接表。因此,我不会接受使用weekday函数的答案。

这两个表的格式都更易于访问。

user_id <- c("aa", "ab", "bb", "bc", "cc")
timestamp <- c("2018-01-01 12:01", "2018-01-01 05:01", "2018-06-01 09:01", "2018-03-03 23:01", "2018-01-02 11:01")

week_id <- seq(1,52)
week_start <- seq(as.Date("2018-01-01"), as.Date("2018-12-31"), 7)
week_end <- week_start + 6

week_start <- week_start[1:52]
week_end <- week_end[1:52]  

table1 <- data.frame(user_id, timestamp)
table2 <- data.frame(week_id, week_start, week_end)

2 个答案:

答案 0 :(得分:1)

使用SQL可以在这样的范围内联接两个表。这似乎是最直接表达我们意图的最优雅的解决方案,但我们还在下面提供了一些替代方案。

library(sqldf)

DF1$date <- as.Date(DF1$timestamp)

sqldf("select * 
  from DF1 a 
  left join DF2 b on date between week_start and week_end")

给予:

  user_id           timestamp       date week_id week_start   week_end
1      aa 2018-01-01 12:01:00 2018-01-01       1 2018-01-01 2018-01-07
2      ab 2018-01-01 05:01:00 2018-01-01       1 2018-01-01 2018-01-07
3      bb 2018-06-01 09:01:00 2018-06-01      NA       <NA>       <NA>
4      bc 2018-03-03 23:01:00 2018-03-04      NA       <NA>       <NA>
5      cc 2018-01-02 11:01:00 2018-01-02       1 2018-01-01 2018-01-07

dplyr

在评论中,发帖人询问是否可以在dplyr中完成。由于dplyr不支持复杂的联接,因此无法直接完成,但是一种解决方法是对两个数据帧进行完全交叉联接,从而产生nrow(DF1) * nrow(DF2)中间结果,然后将其过滤掉。 dplyr不直接支持交叉连接,但是我们可以通过对完全相同的伪常量列进行完全连接来模拟一个交叉连接,该伪常量列将附加到完全连接中的两个数据帧上。由于我们实际上需要在这里进行右连接以加回不匹配的行,因此我们对原始DF1数据帧进行了最后的右连接。显然,对于足够大的输入,这是完全不切实际的,但对于此处的小输入,我们可以做到。如果知道DF2中与DF1中的每一行都匹配,那么末尾的right_join可以省略。

DF1 %>% 
  mutate(date = as.Date(timestamp), dummy = 1) %>%
  full_join(DF2 %>% mutate(dummy = 1)) %>%
  filter(date >= week_start & date <= week_end) %>%
  select(-dummy) %>%
  right_join(DF1)

R Base

findixDF2中找到与日期d相对应的索引。然后,我们在与sapply行相对应的日期上DF1,将DF1和对应的DF2行放在一起。

findix <- function(d) c(which(d >= DF2$week_start & d <= DF2$week_end), NA)[1]
cbind(DF1, DF2[sapply(as.Date(DF1$timestamp), findix), ])

注意

使用的可复制形式的输入数据为:

Lines1 <- "user_id     timestamp
aa          2018-01-01 12:01 UTC
ab          2018-01-01 05:01 UTC
bb          2018-06-01 09:01 UTC
bc          2018-03-03 23:01 UTC
cc          2018-01-02 11:01 UTC"
DF1 <- read.csv(text = gsub("     +", ",", Lines1), strip.white = TRUE)
DF1$timestamp <- as.POSIXct(DF1$timestamp)

Lines2 <- "week_id    week_start     week_end
1          2018-01-01     2018-01-07
2          2018-01-08     2018-01-15
3          2018-01-16     2018-01-23
4          2018-01-23     2018-01-30"
DF2 <- read.table(text = Lines2, header = TRUE)
DF2$week_start <- as.Date(DF2$week_start)
DF2$week_end <- as.Date(DF2$week_end)

答案 1 :(得分:0)

fuzzyjoin包就是这种情况。使用match_fun-参数,我们可以为每一列指定条件。在这种情况下,table1$date >= table2$week_starttable1$date <= table2$week_end

library(fuzzyjoin)
library(lubridate)

table1$date <- as.Date(table1$timestamp)

fuzzy_left_join(table1, table2, 
                by = c("date" = "week_start", "date" = "week_end"),
                match_fun = list(`>=`, `<=`)) %>%
  mutate(day_of_week = wday(date, label = TRUE)) %>%
  select(user_id, timestamp, week_id, day_of_week) 

  user_id        timestamp week_id day_of_week
1      aa 2018-01-01 12:01       1          Mo
2      ab 2018-01-01 05:01       1          Mo
3      bb 2018-06-01 09:01      22          Fr
4      bc 2018-03-03 23:01       9          Sa
5      cc 2018-01-02 11:01       1          Di

我也是一个聪明人,因为我没有使用weekday函数,而是使用lubridate软件包中的wday。