【问题标题】:If else statement to filter out rows using dates and matching values across multiple columns in RIf else 语句使用日期和匹配值在 R 中的多个列中过滤掉行
【发布时间】:2021-09-24 14:26:41
【问题描述】:

我正在尝试使用if else 做一个相当复杂的过滤器,但我一直在转圈。

以下是数据示例:

individual_id born        mom_id trap_date 
        13212 2013-03-16  11926  2014-06-26
        13213 2013-03-16  11926  2013-07-23
        13214 2013-03-16  11926  2015-06-01
        13212 2013-03-16  11926  2014-06-26
        11926 2010-04-08  10422  2013-01-23
        11926 2010-04-08  10422  2013-02-01
        11926 2010-04-08  10422  2013-03-08
        11926 2010-04-08  10422  2013-03-12
        11926 2010-04-08  10422  2013-04-23
        11926 2010-04-08  10422  2013-05-01
        11926 2010-04-08  10422  2013-08-23
        11926 2010-04-08  10422  2013-09-01
        11926 2010-04-08  10422  2013-10-23
        11926 2010-04-08  10422  2013-12-01

我有一个名为mom_id 的专栏,这些人也出现在individual_id 专栏中。

我想删除所有出现的 trap_date 记录 - 距离 born 日期 35 天或 + 70 天的 mom_id仅当她也出现在individual_id 专栏。

因此,在此示例中,我想删除 2013 年 2 月 9 日 (2013-02-09) 和 2013 年 5 月 25 日 (2013-05-25) 之间的所有 trap_date 记录/行,因为 born 日期mom_id 11926 是 2013 年 3 月 16 日 (2013-03-16)。

想要的结果:

individual_id born        mom_id trap_date 
        13212 2013-03-16  11926  2014-06-26
        13213 2013-03-16  11926  2013-07-23
        13214 2013-03-16  11926  2015-06-01
        13212 2013-03-16  11926  2014-06-26
        11926 2010-04-08  10422  2013-01-23
        11926 2010-04-08  10422  2013-02-01
        11926 2010-04-08  10422  2013-08-23
        11926 2010-04-08  10422  2013-09-01
        11926 2010-04-08  10422  2013-10-23
        11926 2010-04-08  10422  2013-12-01

我们将不胜感激dplyr 的解决方案,但在这一点上我将不胜感激!

【问题讨论】:

  • 也许,我被误导了,但我相信 mom_id 11926 的出生日期是 2010-04-08 而不是 2013-03-16,这是 mom_id 19262 的出生日期,不是吗? id 看起来非常相似。
  • 这是一个公平的问题!因为个人同时出现在mom_idindividual_id 列中,所以很难弄清楚born 对应的是什么。但是,born 是必须从mom_id 过滤的日期(因此mom_id==11926born 日期为2013-03-16mom_id==10422born 日期为2010-04-08)。
  • 感谢您的澄清!

标签: r if-statement filter dplyr


【解决方案1】:

我认为这可以满足您的需求。

mutate(df, in_individual = mom_id %in% individual_id) %>%
    filter((!in_individual) | ((born - 35 <= trap_date) & (trap_date <= born + 70)))

【讨论】:

  • 您的解决方案中有错字吗?我收到此错误:Error: unexpected '&lt;=' in: " in_individual = mom_id %in% individual_id) %&gt;% filter((!in_id) || born - 35 &lt;= trap_date &lt;="
  • 对不起,我忘了 R 不支持链接比较运算符。我已经编辑了我的答案。
【解决方案2】:

首先我们将borntrap_date 都转换为日期,以防它们只是文本。然后我们检查mom_id。最后,我们检查trap_date

df %>%
  mutate(
    across(c(born, trap_date), lubridate::ymd), # applies ymd parser over both columns
    in_individual = mom_id %in% individual_id,
    within_interval = 
      trap_date %within% 
        interval(
          start = born - 35,
          end = .born + 70)) %>%
    filter(in_individual, within_interval) # filter out conditional on both

编辑

df %>%
  mutate(
    across(c(born, trap_date), lubridate::ymd), # applies ymd parser over both columns
    in_individual = mom_id %in% individual_id,
    within_interval = purrr::map2_lgl(
      .x = trap_date,
      .y = born,
      .f = ~ .x %within%
        interval(
          start = .y - 35,
          end = .y + 70)) %>%
    filter(in_individual, within_interval) # filter out conditional on both

【讨论】:

  • 在您的解决方案的区间内部分,我收到一个错误:Error: Problem with mutate() input within_interval
  • 我已经编辑了我的答案。映射两个输入应该可以正常工作。
【解决方案3】:

如果我理解正确的话,这可以使用非等反加入来解决

library(data.table)
df2 <- unique(setDT(df1)[, .(mom_id, lo = born - 35, hi = born + 70)])
df1[!df1[df2, on = c("individual_id == mom_id", "trap_date >= lo", "trap_date <= hi"),
    nomatch = NULL, which = TRUE]]
    individual_id       born mom_id  trap_date
 1:         19262 2013-03-16  11926 2014-06-26
 2:         19263 2013-03-16  11926 2013-07-23
 3:         19264 2013-03-16  11926 2015-06-01
 4:         19262 2013-03-16  11926 2014-06-26
 5:         11926 2010-04-08  10422 2013-01-23
 6:         11926 2010-04-08  10422 2013-02-01
 7:         11926 2010-04-08  10422 2013-08-23
 8:         11926 2010-04-08  10422 2013-09-01
 9:         11926 2010-04-08  10422 2013-10-23
10:         11926 2010-04-08  10422 2013-12-01

解释

  • 对于每个唯一的mom_id,计算要删除的日期范围lohi。所以,df2 变成了

       mom_id         lo         hi
    1:  11926 2013-02-09 2013-05-25
    2:  10422 2010-03-04 2010-06-17
    
  • 现在,要删除的行的行号由非等连接标识

     df1[df2, on = c("individual_id == mom_id", "trap_date >= lo", "trap_date <= hi"),
         nomatch = NULL, which = TRUE]  
    

    返回

    [1] 7 8 9 10

  • 最后,这些行通过子集从df1 中删除(使用!

数据

library(data.table)
df1 <- fread("individual_id born        mom_id trap_date 
        19262 2013-03-16  11926  2014-06-26
        19263 2013-03-16  11926  2013-07-23
        19264 2013-03-16  11926  2015-06-01
        19262 2013-03-16  11926  2014-06-26
        11926 2010-04-08  10422  2013-01-23
        11926 2010-04-08  10422  2013-02-01
        11926 2010-04-08  10422  2013-03-08
        11926 2010-04-08  10422  2013-03-12
        11926 2010-04-08  10422  2013-04-23
        11926 2010-04-08  10422  2013-05-01
        11926 2010-04-08  10422  2013-08-23
        11926 2010-04-08  10422  2013-09-01
        11926 2010-04-08  10422  2013-10-23
        11926 2010-04-08  10422  2013-12-01")

【讨论】:

  • 我应该安装其他软件包吗? R 告诉我它找不到函数“。”
  • @BlunderingEcologist,我能够重现该问题。它可以通过将df1 强制转换为data.table 来修复。看我的更新。给您带来的不便,我深表歉意。
猜你喜欢
  • 1970-01-01
  • 2018-12-11
  • 2012-09-19
  • 2020-11-09
  • 1970-01-01
  • 1970-01-01
  • 2021-03-16
  • 2021-05-05
  • 1970-01-01
相关资源
最近更新 更多