查找具有范围的值的重复项,并用R求和

查找具有范围的值的重复项,并用R求和,r,duplicates,range,R,Duplicates,Range,我确实有一个ID为value1、value2和value3的df,看起来如下所示: ID val1 val2 val3 01 100.5 7.31 1000 02 100.0 7.33 100 03 100.1 10.40 500 04 105.3 7.28 100 05 100.4 7.30 500 val1和val2有范围,让我们假设以下范围:val1=0.5和val=0.1 ID val1

我确实有一个ID为value1、value2和value3的df,看起来如下所示:

ID    val1   val2   val3
01   100.5   7.31   1000
02   100.0   7.33    100
03   100.1  10.40    500
04   105.3   7.28    100
05   100.4   7.30    500
val1和val2有范围,让我们假设以下范围:val1=0.5和val=0.1

ID     val1        val2       val3
01   100.5±0.5    7.31±0.1    1000
02   100.0±0.5    7.33±0.1    100
03   100.1±0.5   10.40±0.1    500
04   105.3±0.5    7.28±0.1    100
05   100.4 ±0.5   7.30±0.1    500
我想总结一下在val1和val2范围内重叠的行。只有当这两个条件为真时,才应发生val3之和。最后,该表应仅包含ID较低的行和汇总值3。在我的示例中,这仅适用于第一行、第二行和最后一行。此外,所有不符合这两个标准的行都应该保留。这就是我想要的结果:

ID    val1   val2   val3
01   100.5   7.31   1600
03   100.1  10.40    500
04   105.3   7.28    100
到目前为止,我试图通过
distinct
函数实现这一点。然而,这并没有考虑我的范围和总结

sum_up <- distinct(df, val1, val2, .keep_all = TRUE)

sum\u upEDIT:我对此做了更多的思考,并提出了一个更优雅的解决方案,可以处理任意长的数据帧。该解决方案假定数据已根据ID排序

n <- nrow(data)
used <- logical(n)
groups <- numeric(n)
i <- 1

for (j in 1:n) {
  
  if (used[j]) next
  
  indices1 <- abs(val1[j] - val1) <= range1
  indices2 <- abs(val2[j] - val2) <= range2
  indices <- which(indices1 & indices2 & !used)
  
  groups[indices] <- i
  used[indices] <- TRUE
  i <- i + 1
}

现在可以使用附加列进行分组。不过,我希望您的数据帧没有太多行。这将导致解决方案效率低下。

请注意,您要求这两个条件都为真,而这仅发生在ID 01中。然而,对于您的预期输出,如果第一个条件(val1)为真,您看起来就没事了。您能否更新您的问题以澄清?99.8(第3行)是否与第100行(第2行)重叠?还是每行只重叠一次?@JakobGepp:你说得对,第(2)行的99.8与100.0重叠,但第2行的值不重叠。我只想总结一下满足这两个条件的行。@BenNorris:我试图澄清我的问题,因此我添加了同时满足这两个条件的行(5)。只有符合这两个条件的行才应合并,所有其他行都应保留。作为引用的是ID最低的行还是最近的行?假设A行与B行重叠,B行与D行重叠,但A行与D行不重叠。您是否将这三行相加,因为B行是公共链接?还是D行开始了一个新的分组?谢谢你的解决方案,我适应了我的代码。我最终得到了一个结果表,但是您已经担心我当前使用的数据集有几行(~3000)。这会导致渲染时间过长。。。Markus描述的链接(总是ID最低的链接)正是我的目标。我已经用一个不同的解决方案更新了答案,这个解决方案要短得多,可能更具表现力,并且应该可以处理较长的数据帧。
data <- data.frame(
  ID = 1:5,
  val1 = c(100.5, 100, 100.1, 105.3, 100.4),
  val2 = c(7.31, 7.33, 10.4, 7.28, 7.3),
  val3 = c(1000, 100, 500, 100, 500),
  groups = rep(0, 5)
)

range1 <- .5
range2 <- .1

overlap1 <- abs(outer(data[, "val1"], data[, "val1"], "-")) <= range1
overlap2 <- abs(outer(data[, "val2"], data[, "val2"], "-")) <= range2
overlap_both <- overlap1 & overlap2

result <- list()
ignore <- numeric(ncol(overlap_both))

for (i in 1:ncol(overlap_both)) {
  for(j in i:ncol(overlap_both)) {
    
    # Ignore this index if the element was already combined with a previous
    # element. Otherwise a row in the dataframe would fall in two different
    # groups.
    if (j %in% ignore) {
      next
    }
    
    if (any(overlap_both[, i] & overlap_both[, j])) {
      result[[length(result) + 1]] <- overlap_both[, i] | overlap_both[, j]
      ignore[[j]] <- j
    }
  }
}

result <- unique(result)

for (i in seq_along(result)) {
  data[which(result[[i]]), "groups"] <- i
}