【问题标题】:Remove rows based on condition and date difference between different events in R with dplyr使用 dplyr 根据 R 中不同事件之间的条件和日期差异删除行
【发布时间】:2020-09-30 15:03:00
【问题描述】:

我希望根据不同事件之间的几个条件和日期差异删除行,每个 ID。

我的数据是这样的

#dat
id  name                    date
10  "BREEDING"              2019-05-17
10  "OTHER"                 2020-01-01
11  "BREEDING"              2020-07-01
11  "GESTATION POSITIF"     2020-09-01
12  "BREEDING"              2020-06-26
12  "GESTATION NEGATIF"     2020-08-01
21  "OTHER"                 2018-06-20
21  "GESTATION POSITIF"     2018-10-15
22  "BREEDING"              2020-08-07
22  "GESTATION POSITIF"     2020-09-11

根据 ID,我希望对于那些名为“BREEDING”和“GESTATION”的人(无论是正数还是负数)计算事件“GESTATION”和事件“育种”。

那么如果日期差为34、35、36,则删除对象dat内符合该条件的BREEDING行。

我有一个循环解决方案正在完成这项工作,但我想改进它。我做了几次尝试,但都没有成功。基本上我认为正确的代码应该是“像”这样的

dat %>% 
group_by(id) %>% 
grepl("GESTATION",name) %>% #keep ids with an event gestation recorded
grepl("BREEDING",name) %>% #keep ids with an event breeding recorded
mutate(new_var = "date GESTATION"-"date BREEDING") %>%#per ids, compute de difference of date beetween events gestation event and breeding
filter(!(new_var %in% c(34:36))) %>% #if an event of breeding happened 35 days before the gestation event, +/- 1 day, remove 
ungroup()

最后我的结果应该是,对于这个例子,

#dat
id  name                    date
10  "BREEDING"              2019-05-17
10  "OTHER"                 2020-01-01
11  "BREEDING"              2020-07-01
11  "GESTATION POSITIF"     2020-09-01
12  "GESTATION NEGATIF"     2020-08-01
21  "OTHER"                 2018-06-20
21  "GESTATION POSITIF"     2018-10-15
22  "GESTATION POSITIF"     2020-09-11

【问题讨论】:

  • 某个id会不会有多个“BREEDING”和“GESTATION”?
  • @DarrenTsai 是的,这是可能的。

标签: r dplyr filtering


【解决方案1】:

这也可能不是最干净的解决方案,而是转向宽幅,然后回到长篇作品:

library(tidyverse)
library(lubridate)

dat %>%
  separate(name, into = c("name", "gest"), fill = "right") %>%
  pivot_wider(names_from = name, values_from = c(date, gest)) %>%
  mutate(date_BREEDING = if_else((date_GESTATION - date_BREEDING) %in% c(34, 35, 36), NA_Date_, date_BREEDING)) %>%
  pivot_longer(cols = c(date_BREEDING, date_OTHER, date_GESTATION), values_to = "date", values_drop_na = T) %>%
  select(-gest_BREEDING, -gest_OTHER) %>%
  mutate(name = str_sub(name, 6)) 

输出是:

     id gest_GESTATION name      date      
  <dbl> <chr>          <chr>     <date>    
1    10 NA             BREEDING  2019-05-17
2    10 NA             OTHER     2020-01-01
3    11 POSITIF        BREEDING  2020-07-01
4    11 POSITIF        GESTATION 2020-09-01
5    12 NEGATIF        GESTATION 2020-08-01
6    21 POSITIF        OTHER     2018-06-20
7    21 POSITIF        GESTATION 2018-10-15
8    22 POSITIF        GESTATION 2020-09-11

这具有将“GESTATION”是正数还是负数保存在单独变量中的额外优势。如果您不需要它并且想要在您的问题中指定所需的输出,您可以添加:

%>%
  mutate(name = if_else(is.na(gest_GESTATION), name, str_c(name, gest_GESTATION, sep = " "))) %>%
  select(-gest_GESTATION)

【讨论】:

  • 你的代码有很多错误!你介意分享dput()使用的数据吗?
  • 只需使用问题中指示的数据即可。确保日期列具有date 格式。如果它没有使用as.Date 转换它。由于问题中的代码使用了大量dplyr 管道,我还假设加载所有tidyverse 包作为我回答的先决条件。我现在正在相应地更新它。
  • 你已经从lubridate使用了NA_Date_,所以你必须加载它;否则会出现错误! lubridate 不包含在 tidyverse 中。另外,在加载lubridate之后,还有来自separate()的警告信息。你可以设置fill = "right"来解决。
  • 您的回答很有趣,但我真的无法将“名称”列分开。该变量可以获取大量不同的信息。
  • 最后我仍然使用我的循环。因为一种动物可以有许多不同的事件,以及“繁殖”或“妊娠”的几个事件,即使在同一个活动期间也是如此。
猜你喜欢
  • 2016-01-15
  • 2013-07-17
  • 2021-11-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-31
相关资源
最近更新 更多