在每个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)
我只能考虑从df
开始按id
分组,如下所示:
library(dplyr)
dfnew <- df %>% group_by(id)
但是,我不确定如何从这里继续。我应该继续filter
功能还是slice
?如果是这样,怎么样?
答案 0 :(得分: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
这将为您提供两个额外的列,但这不是一个特殊的IMO。从逻辑上讲,这是有道理的,我已经在不同的场景中成功测试了它,但它可能需要一些额外的验证测试。
答案 1 :(得分:3)
使用slice
中的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)))
}
此功能在从date
开始的ind = 1
列上运行。然后,它会找到下一个索引ind.next
,该索引是first
索引,其日期大于90天(至少91天),距ind
索引的日期。请注意,如果没有ind.next
,ind.next==NA
,我们只返回ind
。否则,我们从f
开始递归调用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
使用此函数假定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