【问题标题】:dplyr: left_join where df A value lies between df B valuesdplyr:left_join,其中 df A 值位于 df B 值之间
【发布时间】:2018-01-31 22:06:29
【问题描述】:

我想知道是否可以使用 dplyr 或一些 tidyverse 包来实现以下...

上下文:我无法将我的数据放入允许使用geom_rect 的结构中。有关动机,请参阅this SO question

library(tis)

# Prepare NBER recession start end dates.
recessions <- data.frame(start = as.Date(as.character(nberDates()[,"Start"]),"%Y%m%d"),
                    end= as.Date(as.character(nberDates()[,"End"]),"%Y%m%d"))

dt <- tibble(date=c(as.Date('1983-01-01'),as.Date('1990-10-15'), as.Date('1993-01-01')))

期望的输出:

date       start      end
1983-01-01 NA         NA
1990-10-15 1990-08-01 1991-03-31
1993-01-01 NA         NA

感谢任何建议。

注意:之前的问题表明sqldf 是一种可以采用的方法。但是,这里的数据涉及到日期,我理解的日期不是 SQLite 中的数据类型。

本着“编写您希望拥有的代码”的精神:

df <- dt %>%
      left_join(x=., y=recessions, date >= start & date <= end)

【问题讨论】:

  • This response 包含对日期时间范围的一些类似要求,并受 sqldf 支持。
  • fuzzyjoin 也可能有一些用处。

标签: r dplyr tidyverse


【解决方案1】:

"Date" R 中的类对象在内部存储为自 Epoch(1970 年 1 月 1 日)以来的天数,并且该数字是发送到 SQLite 的,因此即使该类不是,仍然保持顺序;因此,我们可以使用 SQLite 后端来做到这一点:

sqldf("select * from dt left join recessions on date between start and end")

给予:

        date      start        end
1 1983-01-01       <NA>       <NA>
2 1990-10-15 1990-08-01 1991-03-31
3 1993-01-01       <NA>       <NA>

另请注意,sqldf 可与其他几个完全支持日期的后端一起使用,因此您不限于 SQLite。建议您查看https://github.com/ggrothendieck/sqldf 的常见问题解答和示例。

【讨论】:

  • 我注意到 dplyr 只处理内存问题,sqldf 不会。
【解决方案2】:

以下仅使用 dplyr 并生成所需的数据帧结果。 注意:在较大的数据集上,您可能会遇到内存问题,而 G. Grothendieck 提出的 sqldf 将起作用。

提示: @nick-criswell 将我引导至 @ian-gow 以获取 this partial solution

# Build data frame of dates within the interval [start, end]
df1 <- dt %>% 
        mutate(dummy=TRUE) %>% 
        left_join(recessions %>% mutate(dummy=TRUE)) %>% 
        filter(date >= start & date <= end) %>% 
        select(-dummy) 

# Build data frame of all other dates with start=NA and end=NA
df2 <- dt %>% 
        mutate(dummy=TRUE) %>% 
        left_join(recessions %>% mutate(dummy=TRUE)) %>% 
        mutate(start=NA, end=NA) %>%
        unique() %>%
        select(-dummy) 
# Now merge the two.  Overwirte NA values with start and end dates
df <- df2 %>% 
      left_join(x=., y=df1, by="date") %>%
      mutate(date, start = ifelse(is.na(start.y), as.character(start.x), as.character(start.y)),end = ifelse(is.na(end.y), as.character(end.x), as.character(end.y))) %>%
      mutate(start=as.Date(start), end=as.Date(end) )

> df
# A tibble: 3 x 3
        date      start        end
      <date>     <date>     <date>
1 1983-01-01         NA         NA
2 1990-10-15 1990-08-01 1991-03-31
3 1993-01-01         NA         NA

【讨论】:

    猜你喜欢
    • 2021-10-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-29
    • 2018-10-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多