2013-04-25 63 views
3

我有以下排序向量:如何修剪的R矢量?

> v 
[1] -1 0 1 2 4 5 2 3 4 5 7 8 5 6 7 8 10 11 

我怎樣才能去除-1,0和11項沒有遍歷整個矢量,無論是與用戶環路或隱式語言的關鍵字?也就是說,我想在每個邊緣並且僅在每個邊緣修剪矢量,使得在已排序序列是我分鐘內,最大值參數1和10的解決方案應該假設矢量進行排序以避免檢查每一個元素。

這種解決方案可以派上矢量操作方便非常大的載體,當我們要使用向量中的項目,如在另一個對象的索引。對於一個應用程序,請參閱this thread

回答

4

以前所有的解決方案的隱含檢查向量的每一個元素。作爲@Robert庫布裏克指出,這並不需要的事實矢量已經排序的優勢。

要利用向量的排序自然優勢,您可以使用二進制搜索(通過findInterval)找到起點和終點指標不看的每一個元素:

n<-1e9 
v<--3:(n+3) 
system.time(a <- v [v>=1 & v <=n]) # 68 s 
system.time(b <- v[do.call(seq,as.list(findInterval(c(1,n),v)))]) # 15s 
identical(a,b) # TRUE 

這是一個有點笨拙,並有some discussionfindInterval二進制搜索可能不完全有效的,但一般的概念是存在的。


正如在評論中指出的那樣,上述僅在索引處於向量中時才起作用。這是我認爲會起作用的一個功能:

in.range <- function(x, lo = -Inf, hi = +Inf) { 
    lo.idx <- findInterval(lo, x, all.inside = TRUE) 
    hi.idx <- findInterval(hi, x) 
    lo.idx <- lo.idx + x[lo.idx] >= lo 
    x[seq(lo.idx, hi.idx)] 
} 

system.time(b <- in.range(v, 1, n) # 15s 
+1

對於已排序的向量肯定會更快,但如果最小/最大元素包含在原始向量中,就會如@ flodel所指出的那樣工作。 – 2013-04-25 19:15:46

+0

如果您好奇,我嘗試了'head' /'tail'方法和另一種方法,並將基準添加到我原來的問題中。 – 2013-04-25 19:44:15

+0

@ flodel我喜歡編輯。我的功能很難看。 「all.inside」參數是矢量化的嗎?你可以做'findInterval(c(lo,hi),x,all.inside = c(TRUE,FALSE))' – nograpes 2013-04-25 19:59:09

9

要包含在載體中的元件由指數:

v [2:10] 

排除某些元件

v [-c (1, 11) ] 

只包括在一定範圍內:

v <- v [v>=1 & v <=10] 

如果我我們可以假設,就像在y中一樣我們的例子中,要修剪的元素數量< <在向量元素的話,我想我能擊敗二進制搜索次數:

> n<-1e8 
> v<--3:(n+3) 
> 
> min <- 1 
> max <- length(v) 
> 
> calcMin <- function(v, minVal){ 
+ while(v[min] < minVal){ 
+  min <- min + 1 
+ } 
+ min 
+ } 
> 
> calcMax <- function(v, maxVal){ 
+ while(v[max] > maxVal){ 
+  max <- max - 1 
+ } 
+ max 
+ } 
> 
> #Compute the min and max indices and create a sequence 
> system.time(a <- v[calcMin(v, 1):calcMax(v,n)]) 
    user system elapsed 
    1.030 0.269 1.298 
> 
> #do a binary search to find the elements (as suggested by @nograpes) 
> system.time(b <- v[do.call(seq,as.list(findInterval(c(1,n),v)))]) 
    user system elapsed 
    2.208 0.631 2.842 
> 
> #use negative indexing to remove elements 
> system.time(c <- v[-c(1:(calcMin(v, 1)-1), (calcMax(v,n)+1):length(v))]) 
    user system elapsed 
    1.449 0.256 1.704 
> 
> #use head and tail to trim the vector 
> system.time(d <- tail(head(v, n=(calcMax(v,n)-length(v))), n=-calcMin(v, 1)+1)) 
    user system elapsed 
    2.994 0.877 3.871 
> 
> identical(a, b) 
[1] TRUE 
> identical(a, c) 
[1] TRUE 
> identical(a, d) 
[1] TRUE 
+0

+1 - 最後一個是OP要求的。這也是最快的解決方案。(編輯:我用'&'替換'&&') – flodel 2013-04-25 17:12:58

+0

+1你的答案是正確的,我的選擇是你的:D – 2013-04-25 17:30:25

+1

@ flodel只是好奇,這是如何更快?它沒有任何有關矢量排序性質的知識。 – 2013-04-25 17:44:20

5

有很多方法可以做到這一點,這裏的一些:

> v <- -1:11 # creating your vector 
> v[v %in% 1:10] 
[1] 1 2 3 4 5 6 7 8 9 10 
> setdiff(v, c(-1,0,11)) 
[1] 1 2 3 4 5 6 7 8 9 10 
> intersect(v, 1:10) 
[1] 1 2 3 4 5 6 7 8 9 10 

兩個更多的選擇,而不是那麼優雅。

> na.omit(match(v, 1:10)) 
> na.exclude(match(v, 1:10)) 
+1

在算法上,設置包含比檢查一對夫婦的不平等慢得多。想象一下,如果邊界不是'1'和'10',而是'-1e8'和'1e8' ...... @Robert,Jilber,agstudy,我勸你重新考慮一下。傑夫是正確的答案。 – flodel 2013-04-25 17:18:53

+0

@flodel你在問什麼已經在Jeff Allen的帖子中回答過了,不是嗎? 'v [v> = 1&v <= 10]'或者更一般地說'v [v> =下限和v <上限]' – 2013-04-25 17:25:03

+0

是的,我正試圖引起注意。 – flodel 2013-04-25 17:26:15

2

您可以使用%in%也:

vv <- c(-1, 0 ,1 ,2 ,4 ,5, 2 ,3 ,4, 5, 7 ,8, 5, 6, 7, 8, 10, 11) 
vv[vv %in% 1:10] 

[1] 1 2 4 5 2 3 4 5 7 8 5 6 7 8 10