2012-11-20 42 views
17

R中的大findInterval()函數使用左關閉在其vec參數子間隔,如圖其文檔:findInterval()與右關閉間隔

如果i <- findInterval(x,v),我們有v[i[j]] <= x[j] < v[i[j] + 1]

如果我想要右閉合子區間,我有什麼選擇?我想出的最好的是這樣的:

findInterval.rightClosed <- function(x, vec, ...) { 
    fi <- findInterval(x, vec, ...) 
    fi - (x==vec[fi]) 
} 

另一種也適用:

findInterval.rightClosed2 <- function(x, vec, ...) { 
    length(vec) - findInterval(-x, -rev(vec), ...) 
} 

這裏有一個小測試:

x <- c(3, 6, 7, 7, 29, 37, 52) 
vec <- c(2, 5, 6, 35) 
findInterval(x, vec) 
# [1] 1 3 3 3 3 4 4 
findInterval.rightClosed(x, vec) 
# [1] 1 2 3 3 3 4 4 
findInterval.rightClosed2(x, vec) 
# [1] 1 2 3 3 3 4 4 

但我想看到的任何其他解決方案,如果有更好的。通過「更好」,我的意思是「以某種方式更令人滿意」或「不覺得自己像個混蛋」,或者甚至「更有效率」。 =)

(請注意,有一個rightmost.closed參數findInterval(),但它是不同的 - 它只是指最終的子區間,並具有不同的含義)

+0

你怎麼看待:'findInterval(X,C(-Inf,頭(VEC,-1)))'? – sgibb

+0

@sgibb似乎並沒有做到這一點,我添加了一個例子,你的結果並不一樣。 –

+0

我在這裏有點困惑,但'findInterval(x-1,vec)'做你正在尋找什麼? – thelatemail

回答

10

編輯:專業全部清理過道。您可能會看到cut。默認情況下,cut使左開放和右閉合間隔,並可以使用適當的參數(right)進行更改。要使用你的例子:

x <- c(3, 6, 7, 7, 29, 37, 52) 
vec <- c(2, 5, 6, 35) 
cutVec <- c(vec, max(x)) # for cut, range of vec should cover all of x 

現在創建四個功能應該做同樣的事情:二是從OP,一個來自喬希·奧布萊恩,然後cutcut的兩個參數已從默認設置更改爲:include.lowest = TRUE將爲最小(最左邊)的間隔創建兩側關閉的間隔。 labels = FALSE將導致cut簡單地返回垃圾箱的整數值,而不是創建一個因子,否則它會這樣做。

findInterval.rightClosed <- function(x, vec, ...) { 
    fi <- findInterval(x, vec, ...) 
    fi - (x==vec[fi]) 
} 
findInterval.rightClosed2 <- function(x, vec, ...) { 
    length(vec) - findInterval(-x, -rev(vec), ...) 
} 
cutFun <- function(x, vec){ 
    cut(x, vec, include.lowest = TRUE, labels = FALSE) 
} 
# The body of fiFun is a contribution by Josh O'Brien that got fed to the ether. 
fiFun <- function(x, vec){ 
    xxFI <- findInterval(x, vec * (1 + .Machine$double.eps)) 
} 

所有函數都返回相同的結果嗎?對。 (注意對於cutFun使用cutVec

mapply(identical, list(findInterval.rightClosed(x, vec)), 
    list(findInterval.rightClosed2(x, vec), cutFun(x, cutVec), fiFun(x, vec))) 
# [1] TRUE TRUE TRUE 

現在更苛刻的載體斌:

x <- rpois(2e6, 10) 
vec <- c(-Inf, quantile(x, seq(.2, 1, .2))) 

測試相同(注意使用unname

mapply(identical, list(unname(findInterval.rightClosed(x, vec))), 
    list(findInterval.rightClosed2(x, vec), cutFun(x, vec), fiFun(x, vec))) 
# [1] TRUE TRUE TRUE 

和Benchmark是否:

library(microbenchmark) 
microbenchmark(findInterval.rightClosed(x, vec), findInterval.rightClosed2(x, vec), 
    cutFun(x, vec), fiFun(x, vec), times = 50) 
# Unit: milliseconds 
#        expr  min  lq median  uq  max 
# 1     cutFun(x, vec) 35.46261 35.63435 35.81233 36.68036 53.52078 
# 2      fiFun(x, vec) 51.30158 51.69391 52.24277 53.69253 67.09433 
# 3 findInterval.rightClosed(x, vec) 124.57110 133.99315 142.06567 155.68592 176.43291 
# 4 findInterval.rightClosed2(x, vec) 79.81685 82.01025 86.20182 95.65368 108.51624 

從這次跑步看,cut似乎是最快的。

+0

謝謝。我似乎記得'cut'效率較低,並且它也不允許像'findInterval'那樣追蹤'vec'的右邊緣(請參閱輸出中的第15-17行),但該部分可以工作在最後加入一個'Inf'。 –

+0

@KenWilliams,是的,用'breaks'覆蓋'x'的整個範圍可以讓你切掉所有的'x'(參見我的編輯)。至於效率,那麼代碼至少已經存在了。 – BenBarnes

+0

@KenWilliams,如果你計算效率基準的速度,畢竟'findInterval'和'cut'之間可能沒有太大的區別。 「cut」的減速可能通常來自轉換爲因素和製作標籤? – BenBarnes

-1

如果你的限制是間隔,你可以增加正確的間隔一點點:interval + c(0,0.1)會做:findinterval(value,interval + c(0,0。1))

+0

這不會出於各種原因。最根本的是,回收利用會導致這種情況改變每個奇數條目的正確間隔,而不是全部。此外,這假設您知道數據的離散化寬於0.1。 –

1

也許你可以使用left.open選項:

findInterval(x, vec, left.open=T) 
[1] 1 2 3 3 3 4 4 
+0

是的 - 此選項已添加到2016年10月發佈的R版本3.3.2中。現在是正確的方法。 –

相關問題