我想组合数据框的行,以便“开始”和“结束”列描述的范围包括原始数据集中的所有值。可能存在重叠、重复和嵌套范围。某些范围可能会丢失。
这是我想要折叠的数据类型的示例:
data = data.frame(rbind(
c("Roger", 1, 10),
c("Roger", 10, 15),
c("Roger", 16, 17),
c("Roger", 3, 6),
c("Roger", 20, 25),
c("Roger", NA, NA),
c("Susan", 2, 8)))
names(data) = c("name", "start", "end")
data$start = as.numeric(as.character(data$start))
data$end = as.numeric(as.character(data$end))
期望的结果是:
name start end
Roger 1 17
Roger 20 25
Susan 2 8
我的尝试是扩展每行范围中的每个项目。这可行,但我不知道如何缩小它。此外,我正在使用的完整数据集约有 3000 万行和非常大的范围,因此这种方法非常慢。
pb <- txtProgressBar(min = 0, max = length(data$name), style = 3)
mylist = list()
for(i in 1:length(data$name)){
subdata = data[i,]
if(is.na(subdata$start)){
mylist[[i]] = subdata
mylist[[i]]$each = NA
}
if(!is.na(subdata$start)){
sequence = seq(subdata$start, subdata$end)
mylist[[i]] = subdata[rep(1, each = length(sequence)),]
mylist[[i]]$daily = sequence
}
setTxtProgressBar(pb, i)
}
rbindlist(mylist)
最佳答案
我猜 IRanges 对此更有效,但是......
library(data.table)
# remove missing values
DT = na.omit(setDT(data))
# sort
setorder(DT, name, start)
# mark threshold for a new group
DT[, high_so_far := shift(cummax(end), fill=end[1L]), by=name]
# group and summarise
DT[, .(start[1L], end[.N]), by=.( name, g = cumsum(start > high_so_far + 1L) )]
# name g V1 V2
# 1: Roger 0 1 17
# 2: Roger 1 20 25
# 3: Susan 1 2 8
工作原理:
cummax
是累积最大值,因此是迄今为止的最高值,包括当前行。- 要获取不包括当前行的值,请使用
shift
(从前一行提取)。 cumsum(some_condition)
是创建分组变量的标准方法。.N
是由by=
确定的组的最后一行。
如果需要,可以在最后一步中对列进行命名,例如 .(s = start[1L], e = end[.N])
。
带有日期间隔。如果使用日期,我建议使用 IDate
类;只需使用 as.IDate
转换 Date
即可。
我们可以在日期上+1
,但遗憾的是不能cummax
,所以...
cummax_idate = function(x) (setattr(cummax(unclass(x)), "class", c("Date", "IDate")))
set.seed(1)
d = sample(as.IDate("2011-11-11") + 1:10)
cummax_idate(d)
# [1] "2011-11-14" "2011-11-15" "2011-11-16" "2011-11-18" "2011-11-18"
# [6] "2011-11-19" "2011-11-20" "2011-11-20" "2011-11-21" "2011-11-21"
我认为这个函数可以用来代替cummax
。
函数中额外的 ()
存在,因为 setattr
不会打印其输出。
关于r - 根据日期范围合并行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39046210/