【问题标题】:Merge data sets based on id and date-R根据 id 和 date-R 合并数据集
【发布时间】:2018-04-08 06:41:45
【问题描述】:

我正在尝试根据 ID 和日期将第二个数据集中的信息添加到我的第一个数据集中。如果 ID 匹配并且“日期”介于“开始”和“结束”之间,我想将颜色的值添加到 df1。

    df1
    ID Date 
    1  3/31/2017
    2  2/11/2016
    2  4/10/2016 
    3  5/15/2015

   df2
   ID  start      end        colour
    1   1/1/2000 3/31/2011    blue
    1   4/1/2011  6/4/2012    purple
    1   6/5/2012  3/31/2017   blue
    2   5/1/2014  3/31/2017   red
    3   1/12/2012  2/12/2014  purple

要得到这样的结果:

    dat
    ID Date        colour
    1  3/31/2017   blue
    2  2/11/2016   red
    2  4/10/2016   red
    3  5/15/2015   NA 

可以用这里的代码创建:

library(lubridate)
df1 <- tibble(ID = c(1,2,2,3), Date = mdy(c("3/31/2017","2/11/2016","4/10/2016","5/15/2015")))
df2 <- tibble(ID = c(1,1,1,2,3), start = mdy(c("1/1/2000","4/1/2011","6/5/2012","5/1/2014","1/12/2012")), end = mdy(c("3/31/2011","6/4/2012","3/31/2017","3/31/2017","2/12/2014")), colour = c("blue", "purple", "blue", "red", "purple"))

我使用了一个类似问题的回答, Checking if Date is Between two Dates in R 并使用以下代码:

    library(dplyr)
    dat <- inner_join(df1, df2, by = "ID")
    dat %>% rowwise() %>%
    mutate(match = ifelse(between(df1$Date, df2$start, df2$end), 1 , 0))%>%
    select(-c(df2$start, df2$end))%>%
    arrange(df1$Date, desc(match))%>%
    distinct(df1$Date)

我收到以下错误:

(df1$Date, df2$start, df2$end) 之间的错误: 期望单个值:[extent=355368]。

帮助?

非常感谢!

更新-

非常感谢大家的回答。

我尝试了所有方法,但所有最终数据集的行数都与第一个数据集不同。我不确定发生了什么。我发布的数据是虚构的,类似于我正在使用的数据。我应该让您知道的其他详细信息吗?我不知道从哪里开始...

【问题讨论】:

标签: r date inner-join dplyr


【解决方案1】:

看来你的数据框很大,你可以试试data.table non-equi join 以有效的方式做到这一点:

library(lubridate)
library(data.table)

setDT(df1); setDT(df2)
df1[, Date := mdy(Date)]
df2[, c("start", "end") := .(mdy(start), mdy(end))]

df2[df1, .(ID = i.ID, Date = i.Date, colour), on=.(ID, start <= Date, end >= Date)]

#   ID       Date colour
#1:  1 2017-03-31   blue
#2:  2 2016-02-11    red
#3:  2 2016-04-10    red
#4:  3 2015-05-15     NA

【讨论】:

  • 谢谢。我试过了,但什么也没发生,我没有收到任何错误。
  • 可能是data.table 版本问题。你的data.table 是什么版本?尝试升级它。
  • 您使用的是什么版本?我安装了 1.10.4-2 版本。似乎有更高版本(cran.r-project.org/web/packages/data.table/index.html),但我尝试更新时它没有更新。
  • 我的版本和你的一样。什么也没发生,对我来说没有错误似乎很奇怪。或者您可能需要将结果分配给变量datdat &lt;- df2[df1, .(ID = i.ID, Date = i.Date, colour), on=.(ID, start &lt;= Date, end &gt;= Date)]
  • 哦,是的,当然。现在它可以工作了,但我的行数比我的原始数据集多。
【解决方案2】:

我复制了您的示例并给出了一个解决方案。

library(tidyverse)
library(lubridate)

df1 <- data.frame(ID=c(1, 2, 2, 3), 
                  actual.date=mdy('3/31/2017', '2/11/2016','4/10/2016','5/15/2015')) 

df2 <- data.frame(ID = c(1, 1, 1, 2, 3),
              start = mdy('1/1/2000', '4/1/2011', '6/5/2012', '5/1/2014', '1/12/2012'),
              end = mdy('3/31/2011', '6/4/2012', '3/31/2017', '3/31/2017', '2/12/2014'),
              colour = c("blue", "purple", "blue", "red", "purple"))


df <- full_join(df1, df2, by = "ID") %>% 
  mutate(test = ifelse(actual.date <= end & actual.date > start, 
                       TRUE, 
                       FALSE)) %>% 
  filter(test) %>% 
  left_join(df1, ., by = c("ID", "actual.date")) %>% 
  select(ID, actual.date, colour)

(lubridate包不是必须的,但是输入日期很方便)

下次请提供一个可重现的例子,这样我们就不必手动重写数据了!

【讨论】:

    【解决方案3】:

    使用sqldf的另一种选择

    library(sqldf)
    df1$Date <- as.Date(df1$Date, "%m/%d/%Y")
    df2$start <- as.Date(df2$start, "%m/%d/%Y")
    df2$end <- as.Date(df2$end, "%m/%d/%Y")
    sqldf({"
      SELECT df1.*, df2.colour FROM df1 
      INNER JOIN df2
      ON df1.ID = df2.ID AND df1.Date <= df2.end AND df1.Date >= df2.start
    "})
    

    【讨论】:

      【解决方案4】:

      dplyr 使用non standard evaluation,因此您可以转储所有数据帧名称和$s,您的代码基本上以正确的方向开始。您还需要进行一些隐式转换才能最终得到您指定的数据框,但下面的内容将帮助您实现目标。

      dat <- 
          df1 %>% 
          inner_join(df2) %>%
          rowwise %>% 
          mutate(match = ifelse(between(Date, start, end), 1 , NA)) %>%
          arrange(ID, Date, desc(match)) %>%
          ungroup %>% 
          group_by(ID, Date) %>% 
          mutate(best = row_number(ID), 
                 colour = if_else(is.na(match), NA_character_, colour)) %>%
          filter(best == 1) %>% 
          select(ID, Date, colour) 
      
      > dat
          # A tibble: 4 x 3
          # Groups:   ID, Date [4]
               ID       Date colour
            <dbl>     <date>  <chr>
          1     1 2017-03-31   blue
          2     2 2016-02-11    red
          3     2 2016-04-10    red
          4     3 2015-05-15   <NA>
      

      【讨论】:

        猜你喜欢
        • 2021-10-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-09-20
        • 2022-08-18
        • 1970-01-01
        • 2021-08-06
        相关资源
        最近更新 更多