3

我的数据由 4 列组成:日期、低位、高位和位置。

我试图通过根据位置字段将数据汇总到组中来找到范围。

  1. 如果 diff(position) < 3,则将数据分组在一起并将范围函数应用于每个组。
  2. 如果 diff(position) >= 3 仅计算当前点和前一个点的范围。

前 15 个位置的示例,数据的第 4 个字段:

c(12,14,17,18,19,20,21,22,24,28,33,36,37,38,43)

预期的结果是对, , , ,最后进行分组,(12,14)然后找到每个组的范围。(17:24)(24,28)(28,33)(33,36)(36:38)(38,43)

4

3 回答 3

1

使用IRanges

require(IRanges)
x <- c(12,14,17,18,19,20,21,22,24,28,33,36,37,38,43)
o <- reduce(IRanges(x, width=1), min.gapwidth=2)

给出:

IRanges of length 6
    start end width
# [1]    12  14     3
# [2]    17  24     8
# [3]    28  28     1
# [4]    33  33     1
# [5]    36  38     3
# [6]    43  43     1

这解决了你一半的问题。那些地方width = 1,您想要获得适当的先前值。因此,让我们将其转换为 data.frame。

o <- as.data.frame(o)
o$start[o$width == 1] <- o$end[which(o$width == 1)-1]
o$width <- NULL

#   start end
# 1    12  14
# 2    17  24
# 3    24  28
# 4    28  33
# 5    36  38
# 6    38  43

这给出了最终结果。

编辑:似乎 OP 在所需范围内错过了(14,17)。

ir <- IRanges(x, width = 1)
o1 <- reduce(ir, min.gapwidth = 2)
o2 <- gaps(o1)
start(o2) <- start(o2) - 1
end(o2) <- end(o2) + 1
o1 <- as.data.frame(o1[width(o1) > 1])
o2 <- as.data.frame(o2)
out <- rbind(o1, o2)
out <- out[with(out, order(start, end)), ]

#   start end width
# 1    12  14     3
# 4    14  17     4
# 2    17  24     8
# 5    24  28     5
# 6    28  33     6
# 7    33  36     4
# 3    36  38     3
# 8    38  43     6
于 2013-02-25T20:14:57.920 回答
1

这是一个使用基本 R 函数返回根据所述规则分组的位置索引列表的函数。如果这些值可能不是单调的,并且您只关心绝对差异,我认为更改diff(x)abs(diff(x))(并删除随后的单调性检查)就足够了。

groupIndexes <- function(x, gap=3) {
    d <- diff(x)
    # currently assuming x is in increasing order
    if (any(d<0)) stop("x must be monotonically increasing")
    is.near <- (d < gap)
    # catch case of a single group
    if (all(is.near)) return(list(seq_along(x)))
    runs <- rle(ifelse(is.near, 0, seq_along(is.near)))
    gr <- rep(seq.int(runs$lengths), times=runs$lengths)
    lapply(unique(gr), function(i) {
        ind <- if(runs$values[i]>0) {
            match(i, gr)
        } else {
            which(gr==i)
        }
        c(ind, max(ind)+1)
    })
}

这会自己产生这个分组值:

x <- c(12,14,17,18,19,20,21,22,24,28,33,36,37,38,43)
lapply(groupIndexes(x), function(ind) x[ind])

如果在您的实际情况下您有一个数据框“dat”,您可以根据“位置”列生成组,然后计算“低”列的分组范围,如下所示:

lapply(groupIndexes(dat$position), function(ind) range(dat$low[ind]))
于 2013-02-26T01:51:06.660 回答
1

这是一个diff用于识别组之间界限的选项。

groupBy <- function(dat, thresh=3)  {
    # bounds will grab the *END* of every group (except last element)
    bounds <- which(! diff(dat) < thresh) 

    # add the last index of dat to the "stops" indecies
    stops  <- c(bounds, length(dat))

    # starts are 1 more than the bounds. We also add the first element 
    starts <- c(1, bounds+1) 

    # mapply to get `seq(starts, stops)`
    indecies <- mapply(seq, from=starts, to=stops)

    # return: lapply over each index to get the results
    lapply(indecies, function(i) dat[i])
}

测试:

dat1 <- c(12,14,17,18,19,20,21,22,24,28,33,36,37,38,43)
dat2 <- c(5,6,7,9,13,17,21,35,36,41)

groupBy(dat1)
groupBy(dat2)
groupBy(dat2, 5)
于 2013-02-26T06:54:54.513 回答