【问题标题】:Consolidate rows based on date ranges根据日期范围合并行
【发布时间】:2016-12-27 00:54:39
【问题描述】:

我想组合数据框的行,以便“开始”和“结束”列描述的范围包括原始数据集中的所有值。可能存在重叠、重复和嵌套范围。某些范围可能会丢失。

这是我想要折叠的数据类型的示例:

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)

【问题讨论】:

标签: r date dataframe data.table


【解决方案1】:

我猜 IRange 在这方面效率更高,但是...

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) 是一种创建分组变量的标准方法。
  • .Nby= 确定的组的最后一行。

如果需要,可以在最后一步中将列命名为 .(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 不会打印它的输出。

【讨论】:

  • 我会将na.omit 移动到setDT 之后应用,以便最终使用更快的na.omit.data.table 方法。
  • @这很棒。我实际上将它用于日期范围,但是将日期转换为数字然后返回日期可以使用此方法并保留日期。
  • @Nancy 很高兴听到它正在工作。我已经添加了关于如何处理日期的想法,但不确定它是否会比你正在做的更有效,或者即使它会起作用。
猜你喜欢
  • 1970-01-01
  • 2015-09-28
  • 1970-01-01
  • 2021-08-06
  • 2018-11-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-01
相关资源
最近更新 更多