【问题标题】:Filter rows dataframe based on condition in different dataframe using dplyr使用 dplyr 根据不同数据框中的条件过滤行数据框
【发布时间】:2019-03-29 21:31:13
【问题描述】:

我有两个数据框:df1 和 df2(参见下面的示例)。 df1 包含每个字符 id 的数字开始和结束值。 df2 每个字符 id 包含多个事件,包括数字时间值。

library(dplyr)

df1 <- data_frame(id = c("A", "B"),
                  start = c(2, 3),
                  end = c(5, 9))

df2 <- data_frame(id = c(rep("A", 4), rep("B", 4)),
                  time = c(1, 3, 5, 8, 2, 3, 4, 10),
                  keep = c(FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE))

我正在尝试使用 dplyr 过滤 df2 中的事件,该时间值等于或介于 df1 中每个 id 的开始值和结束值之间。所以过滤器是 "df2$time >= df1$start & df2$time

如何为每个 id 执行此过滤器?最好使用 dplyr。这应该是最终结果:

df2 %>%
  filter(keep == TRUE)

非常感谢任何帮助!

【问题讨论】:

    标签: r dplyr


    【解决方案1】:

    这样的事情怎么样,dplyr:

      df1 %>% 
      left_join(df2) %>%                       #joining to have one dataset
      filter(time <= end, time >= start) %>%   # filter, you can use <, > in case
      select(-c(2,3))                          # remove useless column if necessary
    
    # A tibble: 4 x 3
      id     time keep 
      <chr> <dbl> <lgl>
    1 A         3 TRUE 
    2 A         5 TRUE 
    3 B         3 TRUE 
    4 B         4 TRUE 
    

    【讨论】:

      【解决方案2】:

      使用的非等连接能力:

      # load the package and convert the dataframes to data.tables
      library(data.table)
      setDT(df1)
      setDT(df2)
      
      # non-equi join
      df2[df1
          , on = .(id, time >= start, time <= end)
          , .(id, time = x.time)]
      

      给出:

         id time
      1:  A    3
      2:  A    5
      3:  B    3
      4:  B    4
      

      这是做什么的:

      • setDT() 将 data.frame 转换为 data.table
      • 您加入df1df2。通过使用on = .(id, time &gt;= start, time &lt;= end),您可以加入id 的精确匹配,同时time 必须高于或等于start 来自df1 并且低于或等于end 来自df1
      • 在进行非等值连接时, 将从 df1startend)返回 time 列作为 timetime满足条件(see also here)。要了解我的意思,您可以使用df2[df1, on = .(id, time &gt;= start, time &lt;= end)]
      • 通过使用.(id, time = x.time),您可以获得所需的列。 x.time 指的是 x-data.table 中的 time 列,即 df2

      【讨论】:

        【解决方案3】:

        这也有效

        df2$start <- df1[match(df2$id, df1$id),"start"]
        df2$end <- df1[match(df2$id, df1$id),"end"]
        df2$keep <- df2$time>df2$start& df2$time<df2$end
        result <- df2 %>%  filter(keep)
        result
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-12-21
          • 1970-01-01
          • 2023-03-20
          • 1970-01-01
          • 1970-01-01
          • 2018-09-15
          • 2023-01-10
          • 1970-01-01
          相关资源
          最近更新 更多