Ответ 1
Я не знаю, что это особенно эффективно, но если ваша матрица диапазонов ranges
, тогда должно работать следующее:
unique(unlist(apply(ranges, 1, function(x) x[1]:x[2])))
В R, какой эффективный способ извлечь целые числа из диапазонов?
Скажем, у меня есть матрица диапазонов (column1 = start, column2 = end)
1 5
3 6
10 13
Я хотел бы сохранить в качестве объекта уникальные целые числа всех диапазонов матрицы:
1
2
3
4
5
6
10
11
12
13
Это применимо к матрице, содержащей ~ 4 миллиона диапазонов, поэтому, надеюсь, кто-то может предложить решение, которое несколько эффективно.
Я не знаю, что это особенно эффективно, но если ваша матрица диапазонов ranges
, тогда должно работать следующее:
unique(unlist(apply(ranges, 1, function(x) x[1]:x[2])))
Предположим, что у вас есть start = 3, end = 7, и вы отметили их как "1" на числовой строке, начинающейся с 1
starts: 0 0 1 0 0 0 0 0 0 ...
ends + 1: 0 0 0 0 0 0 0 1 0 ...
Суммарная сумма стартов минус кумулятивная сумма концов, а разница между ними равна
cumsum(starts): 0 0 1 1 1 1 1 1 1 ...
cumsum(ends + 1): 0 0 0 0 0 0 0 1 1 ...
diff: 0 0 1 1 1 1 1 0 0
и расположение 1 в разности
which(diff > 0): 3 4 5 6 7
Используйте табуляцию, чтобы разрешить несколько запусков/концов в одном и том же месте, и
range2 <- function(ranges)
{
max <- max(ranges)
starts <- tabulate(ranges[,1], max)
ends <- tabulate(ranges[,2] + 1L, max)
which(cumsum(starts) - cumsum(ends) > 0L)
}
Для вопроса это дает
> eg <- matrix(c(1, 3, 10, 5, 6, 13), 3)
> range2(eg)
[1] 1 2 3 4 5 6 10 11 12 13
Это довольно быстро, для примера Andrie
> system.time(runs <- range2(xx))
user system elapsed
0.108 0.000 0.111
(это немного похоже на анализ последовательности ДНК, для которого GenomicRanges может быть вашим другом, вы использовали бы coverage
и slice
функции при чтении, возможно, введите readGappedAlignments
).
Используйте sequence
и rep
:
x <- matrix(c(1, 5, 3, 6, 10, 13), ncol=2, byrow=TRUE)
ranges <- function(x){
len <- x[, 2] - x[, 1] + 1
#allocate space
a <- b <- vector("numeric", sum(len))
a <- rep(x[, 1], len)
b <- sequence(len)-1
unique(a+b)
}
ranges(x)
[1] 1 2 3 4 5 6 10 11 12 13
Так как это использует только векторный код, это должно быть довольно быстро, даже для больших наборов данных. На моей машине входная матрица в 1 миллион строк занимает ~ 5 секунд для запуска:
set.seed(1)
xx <- sample(1e6, 1e6)
xx <- matrix(c(xx, xx+sample(1:100, 1e6, replace=TRUE)), ncol=2)
str(xx)
int [1:1000000, 1:2] 265509 372124 572853 908206 201682 898386 944670 660794 629110 61786 ...
system.time(zz <- ranges(xx))
user system elapsed
4.33 0.78 5.22
str(zz)
num [1:51470518] 265509 265510 265511 265512 265513 ...
Разве это не так просто:
x <- matrix(c(1, 5, 3, 6, 10, 13), ncol=2, byrow=TRUE)
do.call(":",as.list(range(x)))
[1] 1 2 3 4 5 6 7 8 9 10 11 12 13
Edit
Похоже, что я получил неправильный конец палки, но мой ответ можно изменить, чтобы использовать union
, хотя это всего лишь оболочка для unique
:
Reduce("union",apply(x,1,function(y) do.call(":",as.list(y))))
[1] 1 2 3 4 5 6 10 11 12 13