如何根据R中行之间的日期差异过滤行?

HNS*_*SKD 10 r dplyr

在每个内部id,我想保留至少相隔91天的行.在我的数据框中df,id=1有5行,id=2有1行.

因为id=1,我想只保留第1行,第3行和第5行.

这是因为如果我们比较第一个日期和第二个日期,它们相差32天.所以,删除第二个日期.我们继续比较第1和第3个日期,它们相差152天.所以,我们保持第3次约会.

现在,我们使用第3个日期,而不是使用第1个日期作为参考.第3个日期和第4个日期相差61天.所以,删除第4个日期.我们继续比较第3个日期和第5个日期,它们相差121天.所以,我们保持第5个约会.

最后,我们保留的日期是第1天,第3天和第5天.至于id=2,只有一行,所以我们保持这一点.期望的结果显示在dfnew.

df <- read.table(header = TRUE, text = "
id  var1  date        
 1  A     2006-01-01 
 1  B     2006-02-02 
 1  C     2006-06-02 
 1  D     2006-08-02 
 1  E     2007-12-01 
 2  F     2007-04-20 
",stringsAsFactors=FALSE)

dfnew <- read.table(header = TRUE, text = "
id  var1  date        
 1  A     2006-01-01 
 1  C     2006-06-02 
 1  E     2007-12-01 
 2  F     2007-04-20 
",stringsAsFactors=FALSE)
Run Code Online (Sandbox Code Playgroud)

我只能想到用分组开始的df通过id如下:

library(dplyr)
dfnew <- df %>% group_by(id)
Run Code Online (Sandbox Code Playgroud)

但是,我不确定如何从这里继续.我应该继续filter功能还是slice?如果是这样,怎么样?

Dav*_*urg 13

这是尝试使用滚动连接data.table,我认为应该是有效的

library(data.table)
# Set minimum distance
mindist <- 91L 
# Make sure it is a real Date
setDT(df)[, date := as.IDate(date)] 
# Create a new column with distance + 1 to roll join too
df[, date2 := date - (mindist + 1L)] 
# Perform a rolling join per each value in df$date2 that has atleast 91 difference from df$date
unique(df[df, on = c(id = "id", date = "date2"), roll = -Inf], by = c("id", "var1"))
#    id var1       date      date2 i.var1     i.date
# 1:  1    A 2005-10-01 2005-10-01      A 2006-01-01
# 2:  1    C 2006-03-02 2006-03-02      C 2006-06-02
# 3:  1    E 2007-08-31 2007-08-31      E 2007-12-01
# 4:  2    F 2007-01-18 2007-01-18      F 2007-04-20
Run Code Online (Sandbox Code Playgroud)

这将为您提供两个额外的列,但这不是一个特殊的IMO.逻辑上这是有道理的,我已经在不同的场景中成功测试了它,但它可能需要一些额外的验证测试.


aic*_*hao 6

使用slicefrom的另一种方法dplyr是定义以下递归函数:

library(dplyr)
f <- function(d, ind=1) {
  ind.next <- first(which(difftime(d,d[ind], units="days") > 90))
  if (is.na(ind.next))
    return(ind)
  else
    return(c(ind, f(d,ind.next)))
}
Run Code Online (Sandbox Code Playgroud)

此函数对date从 开始的列进行操作ind = 1。然后,它查找下一个索引ind.next,该first索引的日期距 索引的日期大于 90 天(至少 91 天)ind。注意,如果没有这样的ind.nextind.next==NA我们就直接返回ind。否则,我们递归调用f从 at 开始ind.next并返回与 串联的结果ind。此函数调用的最终结果是间隔至少 91 天的行索引。

通过这个函数,我们可以做到:

result <- df %>% group_by(id) %>% slice(f(as.Date(date, format="%Y-%m-%d")))
##Source: local data frame [4 x 3]
##Groups: id [2]
##
##     id  var1       date
##  <int> <chr>      <chr>
##1     1     A 2006-01-01
##2     1     C 2006-06-02
##3     1     E 2007-12-01
##4     2     F 2007-04-20
Run Code Online (Sandbox Code Playgroud)

使用此函数假定该date列按每个id组按升序排序。如果没有,我们可以在切片之前对日期进行排序。不确定这个的效率或 R 中递归调用的危险。希望 David Arenburg 或其他人可以对此发表评论。


正如 David Arenburg 所建议的,最好date先转换为 Date 类,而不是按组转换:

result <- df %>% mutate(date=as.Date(date, format="%Y-%m-%d")) %>%
                 group_by(id) %>% slice(f(date))
##Source: local data frame [4 x 3]
##Groups: id [2]
##
##     id  var1       date
##  <int> <chr>     <date>
##1     1     A 2006-01-01
##2     1     C 2006-06-02
##3     1     E 2007-12-01
##4     2     F 2007-04-20
Run Code Online (Sandbox Code Playgroud)