2011-03-07 28 views
11

我有一個載體,如c(1, 3, 4, 5, 9, 10, 17, 29, 30)和我想組,在一個粗糙的矢量形成規則,連續序列導致在一起「相鄰」元素:如何將一個向量分成規則的連續序列組?

L1:1
L2:3,4 ,5
L3:9,10
L4:17
L5:29,30

樸素代碼(的前C程序員):

partition.neighbors <- function(v) 
{ 
    result <<- list() #jagged array 
    currentList <<- v[1] #current series 

    for(i in 2:length(v)) 
    { 
     if(v[i] - v [i-1] == 1) 
     { 
      currentList <<- c(currentList, v[i]) 
     } 
     else 
     { 
      result <<- c(result, list(currentList)) 
      currentList <<- v[i] #next series 
     }  
    } 

    return(result) 
} 

現在我明白了

一)R不是C(儘管大括號)
B)全局變量是純粹的邪惡
c)該是實現的結果

的效率極其低下的方式,所以沒有更好的解決方案歡迎。

回答

3

你可以很容易地定義切點:

which(diff(v) != 1) 

此基礎上嘗試:

v <- c(1,3,4,5,9,10,17,29,30) 
cutpoints <- c(0, which(diff(v) != 1), length(v)) 
ragged.vector <- vector("list", length(cutpoints)-1) 
for (i in 2:length(cutpoints)) ragged.vector[[i-1]] <- v[(cutpoints[i-1]+1):cutpoints[i]] 

導致:

> ragged.vector 
[[1]] 
[1] 1 

[[2]] 
[1] 3 4 5 

[[3]] 
[1] 9 10 

[[4]] 
[1] 17 

[[5]] 
[1] 29 30 

這個算法是不是一個好一個但你可以根據diff :)寫很多整潔的代碼:)祝你好運!

9

daroczig寫道: 「你可以寫一個基於diff很多整潔的代碼」 ...

這裏有一種方法:

split(v, cumsum(diff(c(-Inf, v)) != 1)) 

編輯(添加定時):

湯米發現這可能謹慎使用類型會更快;它得到更快的原因是split整數更快,實際上更快的因素。

這是Joshua的解決方案; cumsum的結果是一個數字,因爲它是c'd與1,所以它是最慢的。

system.time({ 
a <- cumsum(c(1, diff(v) != 1)) 
split(v, a) 
}) 
# user system elapsed 
# 1.839 0.004 1.848 

只是c與荷蘭國際集團1L所以結果是整數其加速增色不少。

system.time({ 
a <- cumsum(c(1L, diff(v) != 1)) 
split(v, a) 
}) 
# user system elapsed 
# 0.744 0.000 0.746 

這是湯米的解決方案,供參考;它也分裂在一個整數。

> system.time({ 
a <- cumsum(c(TRUE, diff(v) != 1L)) 
split(v, a) 
}) 
# user system elapsed 
# 0.742 0.000 0.746 

這是我的原始解決方案;它也分裂在一個整數。

system.time({ 
a <- cumsum(diff(c(-Inf, v)) != 1) 
split(v, a) 
}) 
# user system elapsed 
# 0.750 0.000 0.754 

這裏是約書亞的結果轉換爲split之前的整數。

system.time({ 
a <- cumsum(c(1, diff(v) != 1)) 
a <- as.integer(a) 
split(v, a) 
}) 
# user system elapsed 
# 0.736 0.002 0.740 

所有版本的split上的整數向量是大致相同的;如果整數向量已經是一個因子,那麼它可能會更快,因爲從整數到因子的轉換實際上只需要一半的時間。在這裏我直接把它作爲一個因素;這通常不被推薦,因爲它取決於因素類的結構。這裏僅做比較的目的。

system.time({ 
a <- cumsum(c(1L, diff(v) != 1)) 
a <- structure(a, class = "factor", levels = 1L:a[length(a)]) 
split(v,a) 
}) 
# user system elapsed 
# 0.356 0.000 0.357 
+0

是的,這是很多更合適的方法:然而,他們的代碼仍然可以通過小心地使用正確的類型,整數和邏輯值的比快兩倍多! :)我不知道'split',謝謝你將我的注意力指向這個有用的功能。 – daroczig 2011-03-07 16:46:26

+0

我應該注意,當使用'as.integer'時應該小心,因爲它會返回截斷值,當使用浮點算術創建數值時,這可能不是您想要的,例如'as.integer(0.3 * 3 + 0.1)'返回'0'。 – Aaron 2011-05-13 16:28:16

13

大量使用一些[R成語:

> split(v, cumsum(c(1, diff(v) != 1))) 
$`1` 
[1] 1 

$`2` 
[1] 3 4 5 

$`3` 
[1] 9 10 

$`4` 
[1] 17 

$`5` 
[1] 29 30 
4

可以使用diffifelsecumsum創建data.frame和分配元素組,然後彙總使用tapply

v.df <- data.frame(v = v) 
v.df$group <- cumsum(ifelse(c(1, diff(v) - 1), 1, 0)) 
tapply(v.df$v, v.df$group, function(x) x) 

$`1` 
[1] 1 

$`2` 
[1] 3 4 5 

$`3` 
[1] 9 10 

$`4` 
[1] 17 

$`5` 
[1] 29 30 
4

約書亞和亞倫是現貨。

split(v, cumsum(c(TRUE, diff(v) != 1L))) 

v <- rep(c(1:5, 19), len = 1e6) # Huge vector... 
system.time(split(v, cumsum(c(1, diff(v) != 1)))) # Joshua's code 
# user system elapsed 
# 2.64 0.00 2.64 

system.time(split(v, cumsum(c(TRUE, diff(v) != 1L)))) # Modified code 
# user system elapsed 
# 1.09 0.00 1.12 
+0

哇!我不會猜到它會產生這樣的差異。 – Aaron 2011-05-05 04:37:29

+0

湯米,我想出了爲什麼它更快,並編輯你的文章添加它。我不確定這是不是合適的禮儀;希望你不介意。 (另外,它必須經過同行評審,所以如果你沒有馬上看到它,那就是爲什麼。) – Aaron 2011-05-05 21:04:03

+0

顯然我的編輯被拒絕了;我已將時間添加到我的答案中。 – Aaron 2011-05-13 16:16:46

相關問題