在R中,從範圍中提取整數的有效方法是什麼?從範圍中提取整數
比方說,我有範圍的矩陣(列1 =啓動,列2 =結束)
1 5
3 6
10 13
我想在矩陣中所有範圍的涵蓋唯一整數存儲到一個對象:
1
2
3
4
5
6
10
11
12
13
這將應用於包含400萬範圍的矩陣,所以希望有人可以提供一個有點高效的解決方案。
在R中,從範圍中提取整數的有效方法是什麼?從範圍中提取整數
比方說,我有範圍的矩陣(列1 =啓動,列2 =結束)
1 5
3 6
10 13
我想在矩陣中所有範圍的涵蓋唯一整數存儲到一個對象:
1
2
3
4
5
6
10
11
12
13
這將應用於包含400萬範圍的矩陣,所以希望有人可以提供一個有點高效的解決方案。
我不知道它是特別有效的,但如果你的範圍的矩陣是ranges
那麼下面應該工作:
unique(unlist(apply(ranges, 1, function(x) x[1]:x[2])))
使用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
由於這隻使用矢量化代碼,因此即使對於大型數據集,這也應該相當快。在我的機器的一個百萬行輸入矩陣需要約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 ...
假設你在數軸上有開始= 3,端= 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
(這聽起來有點像DNA seque nce分析,其中GenomicRanges可能是你的朋友;您可以在讀取時使用coverage
和slice
函數,或許使用readGappedAlignments
輸入)。
這比其他兩種解決方案快得多。令人印象深刻。 – seancarmody 2012-08-12 10:32:05
+1精彩... – Andrie 2012-08-12 12:16:19
難道不是簡單:
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
編輯
貌似我得到了棍子的錯誤結束,但我的回答可以被修改爲使用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
請注意,在OP中,7,8和9不會出現在所需的結果中。這個想法是在整個矩陣中返回每個範圍的聯合,而不是整個範圍從最低到最高。 – seancarmody 2012-08-12 10:25:41
@seancarmody啊,我明白了,我誤解了,那麼根據我的想法,你的回答是正確的。我將刪除這個 – James 2012-08-12 10:32:43
其實,我找到了修改它的方法。不完全不同,但是完整性的另一種選擇 – James 2012-08-12 10:46:27
我認爲,OP想要的結果,每個整數只有一次。 – seancarmody 2012-08-12 02:33:27
我比較了時間:我的答案肯定是慢跑! – seancarmody 2012-08-12 02:42:39
@seancarmody感謝您強調**獨特**整數的要求。我會編輯我的答案。 – Andrie 2012-08-12 02:47:44