2014-02-26 29 views
4

我需要找到向量中第二個非序列值的出現索引。如何使用R查找矢量中第二個非連續出現值的索引?

一些示例載體:

例a)1 1 1 2 3 4 1 1 1 2 3 4

例b)1 2 3 1 1 1 3 5

注意,載體可以每個值的出現次數都不相同,並且非常大(超過100000個條目)

因此,如果問題的值爲1,則在示例a)中,結果應該返回第7個位置,並且b)應該返回4。

在此先感謝您提供的任何幫助或建議。

示例代碼:

exampleA<-c(1, 1, 1, 2, 3, 4, 1, 1, 1, 2, 3, 4) 
exampleB<-c(1, 2, 3, 1, 1, 1, 3, 5) 
+0

感謝所有人的快速和全面的幫助。我最終選擇了@josliber的答案,因爲我能夠最輕鬆地遵循邏輯(其他人都貢獻了一些有價值的東西,但一對夫婦超出了我的技能),並且將我介紹給了我不熟悉的外表功能很有用。 –

回答

5

向量的遊程長度編碼可以在這些種類的計算有幫助:

find.index <- function(x, value) { 
    r <- rle(x) 
    match.pos <- which(r$value == value) 
    if (length(match.pos) < 2) { 
    return(NA) # There weren't two sequential sets of observations 
    } 
    return(sum(r$length[1:(match.pos[2]-1)])+1) 
} 

# Test it out 
a <- c(1, 1, 1, 2, 3, 4, 1, 1, 1, 2, 3, 4) 
b <- c(1, 2, 3, 1, 1, 1, 3, 5) 
find.index(a, 1) 
# [1] 7 
find.index(b, 1) 
# [1] 4 
find.index(b, 5) 
# [1] NA 
3

也許whichdiff組合可能是有用的:

x <- which(a == 1) 
x[which(diff(x) != 1)[1] + 1] 
# [1] 7 
y <- which(b == 1) 
y[which(diff(y) != 1)[1] + 1] 
# [1] 4 

這是作爲一個功能:

findFirst <- function(invec, value, event) { 
    x <- which(invec == value) 
    if (event == 1) out <- x[1] 
    else out <- x[which(diff(x) != 1)[event-1] + 1] 
    out 
} 
  • invec是輸入向量。
  • value是你正在尋找的價值。
  • event是位置(例如,第一,第二,第三序列)。

用法是:

findFirst(a, 1, 2) ## event is the occurrence you want to get 

標杆的功能可用迄今:

set.seed(1) 
a <- sample(25, 1e7, replace = TRUE) 
findFirst(a, 10, 2) 
# [1] 14 
find.index(a, 10) 
# [1] 14 
op(a, 10) 
# [1] 14 

library(microbenchmark) 
microbenchmark(findFirst(a, 10, 2), find.index(a, 10), op(a, 10), times = 5) 
# Unit: milliseconds 
#     expr  min  lq median  uq  max neval 
# findFirst(a, 10, 2) 281.6979 284.3281 301.6595 380.9089 414.9640  5 
# find.index(a, 10) 3268.0227 3312.0002 3372.3713 3444.7334 3769.0176  5 
#   op(a, 10) 272.7325 278.3369 280.3172 286.0758 293.6699  5 
2

你可以試試這個:

op <- function(v, x){ # v=vector, x=value 
    w <- which(v==x) # 1) 
    s <- seq(w[1],length.out=length(w)) # 2) 
    return(w[which(w!=s)[1]]) # 3) 
} 

> exampleA <- c(1, 1, 1, 2, 3, 4, 1, 1, 1, 2, 3, 4) 
> exampleB <- c(1, 2, 3, 1, 1, 1, 3, 5) 
> op(exampleA, 1) 
[1] 7 
> op(exampleB, 1) 
[1] 4 
  1. 檢查什麼的向量元素等於x
  2. 從等於x的第一個元素的位置開始構建一個序列s
  3. w==s=TRUE是那些從第一次出現開始連續出現的事件,所以您想要返回第一個出現的位置,即w!=s,即與第一次出現的位置不連續。
+1

+1。看起來很有效率(以我的答案中的基準)。稍微概括一下這個函數會很好。 – A5C1D2H2I1M1N2O1R2T1

+0

@AnandaMahto謝謝檢查! –

2

如果速度是一個很重要的因素(並且閱讀原文,看起來好像是這樣),那麼使用Rcpp的自定義解決方案可能比任何發佈的純R方法都快遠:

library(Rcpp) 
find.second = cppFunction(
"int findSecond(NumericVector x, const int value) { 
    bool startFirst = false; 
    bool inFirst = false; 
    for (int i=0; i < x.size(); ++i) { 
     if (x[i] == value) { 
      if (!startFirst) { 
       startFirst = true; 
       inFirst = true; 
      } else if (!inFirst) { 
       return i+1; 
      } 
     } else { 
      inFirst = false; 
     } 
    } 
    return -1; 
}") 

這裏有@ AnandMahto的基準,擴大到包括find.second

set.seed(1) 
a <- sample(25, 1e7, replace = TRUE) 
findFirst(a, 10, 2) 
# [1] 14 
find.index(a, 10) 
# [1] 14 
op(a, 10) 
# [1] 14 
find.second(a, 10) 
# [1] 14 

microbenchmark(findFirst(a, 10, 2), find.index(a, 10), op(a, 10), find.second(a, 10), times = 5) 
# Unit: milliseconds 
#     expr  min   lq  median   uq  max neval 
# findFirst(a, 10, 2) 79.00000 93.85400 96.80120 118.32011 121.56636  5 
# find.index(a, 10) 1620.83892 1673.72124 1689.06826 1747.42781 2145.90346  5 
#   op(a, 10) 78.54637 83.71081 94.20531 97.30813 195.78469  5 
# find.second(a, 10) 14.57835 24.36220 25.24104 36.57584 47.45959  5 
3

這裏是一個僅改變R實現,它是令人驚訝的速度比RCPP,雖然我們不會在非常深v所以我不知道這是否有意義。

find.index.3 <- function(vec, val) { 
    seq_val <- 0 
    last_val <- NA 
    for(i in seq_along(vec)) { 
    if(identical(vec[[i]], val) & !identical(last_val, val_to_match)) 
     if(identical(seq_val <- seq_val + 1, 2)) break 
    last_val <- vec[[i]] 
    } 
    i 
} 
library(microbenchmark) 
microbenchmark(find.index.3(a, 10L), find.second(a, 10)) 
# Unit: milliseconds 
#     expr  min  lq median  uq  max neval 
# find.index.3(a, 10L) 5.650716 5.877447 6.095766 8.003047 106.4033 100 
# find.second(a, 10) 15.758154 18.143398 18.934030 20.247239 118.1735 100 

關鍵是要避免使用查看整個向量的向量化函數。如果重複實例在向量中很深,這可能會更慢。請注意,identical()據說非常快(編輯:實際上,使用==似乎更快),但它意味着您必須將您的值作爲整數傳遞。

編輯:

RCPP並獲得更快,如果你足夠深入。更改a所以它從10000個值而不是25個樣本中獲得:

# Unit: milliseconds 
#     expr  min  lq median  uq  max neval 
# find.index.3(a, 10L) 80.50039 83.23213 84.27801 85.43654 186.4049 100 
# find.second(a, 10) 17.06515 19.38969 20.52041 23.52533 125.8619 100 
+0

這裏有很深的vs不深的分析 – josliber

+1

@josilber,謝謝你的第二個答案,在這個問題中所有的麻煩都很有趣,這裏的OP跟你最初的慢速答案一樣。 – BrodieG

相關問題