簡體   English   中英

獲得向量之間匹配位置的有效方法

[英]Efficient way to get location of match between vectors

我需要找到兩個向量之間的索引(而不是邏輯向量)的效率。 我可以這樣做:

which(c("a", "q", "f", "c", "z") %in% letters[1:10])

以同樣的方式,最好找到最大數量的位置which.max

which(c(1:8, 10, 9) %in% max(c(1:8, 10, 9)))
which.max(c(1:8, 10, 9))

我想知道我是否有最有效的方法來找到2個向量中匹配項的位置。

編輯:根據下面的問題/評論。 我在矢量列表上運行。 這個問題涉及對句子進行操作,如下所示,這些句子被分解成一個單詞。 該列表可以包含10000-20000或更多字符向量。 然后基於該索引,我將獲得之前的4個單詞和索引之后的4個單詞並計算得分。

x <- list(c('I', 'like', 'chocolate', 'cake'), c('chocolate', 'cake', 'is', 'good'))
y <- rep(x, 5000)

lapply(y, function(x) {
    which(x %in% c("chocolate", "good"))
})

這是使用data.table的一種相對較快的方法:

require(data.table)
vv <- vapply(y, length, 0L)
DT <- data.table(y = unlist(y), id = rep(seq_along(y), vv), pos = sequence(vv))
setkey(DT, y)
# OLD CODE which will not take care of no-match entries (commented)
# DT[J(c("chocolate", "good")), list(list(pos)), by=id]$V1

setkey(DT[J(c("chocolate", "good"))], id)[J(seq_along(vv)), list(list(pos))]$V1

想法:

首先,我們將您的列表取消列入名為yDT列。 另外,我們創建了另外兩個名為idpos列。 id告訴列表中的索引, pos告訴該id的位置。 然后,通過在id上創建關鍵列,我們可以進行快速子集化 通過這個子集,我們將獲得每個id相應pos值。 在我們收集列表中每個id所有pos然后只輸出列表列(V1)之前,我們通過在對所有可能值進行首次子集化和子集化之后將key設置為id來處理那些與我們的查詢不匹配的條目id (因為這將導致NA不存在的條目。


使用lapply上的lapply代碼進行基准測試:

x <- list(c('I', 'like', 'chocolate', 'cake'), c('chocolate', 'cake', 'is', 'good'))
y <- rep(x, 5000)

require(data.table)
arun <- function() {
    vv <- vapply(y, length, 0L)
    DT <- data.table(y = unlist(y), id = rep(seq_along(y), vv), pos = sequence(vv))
    setkey(DT, y)
    setkey(DT[J(c("chocolate", "good"))], id)[J(seq_along(vv)), list(list(pos))]$V1
}

tyler <- function() {
    lapply(y, function(x) {
        which(x %in% c("chocolate", "good"))
    })
}

require(microbenchmark)
microbenchmark(a1 <- arun(), a2 <- tyler(), times=50)

Unit: milliseconds
          expr       min        lq    median        uq       max neval
  a1 <- arun()  30.71514  31.92836  33.19569  39.31539  88.56282    50
 a2 <- tyler() 626.67841 669.71151 726.78236 785.86444 955.55803    50

> identical(a1, a2)
# [1] TRUE

C ++的答案比單個字符更快,但我認為使用字符串向量引入了足夠的開銷,現在它變慢了:

char1 <- c("a", "q", "f", "c", "z")
char2 <- letters[1:10]

library(inline)
cpp_whichin_src <- '
Rcpp::CharacterVector xa(a);
Rcpp::CharacterVector xb(b);
int n_xa = xa.size();
int n_xb = xb.size();

NumericVector res(n_xa);

std::vector<std::string> sa = Rcpp::as< std::vector<std::string> >(xa);
std::vector<std::string> sb = Rcpp::as< std::vector<std::string> >(xb);

for(int i=0; i < n_xa; i++) {
  for(int j=0; j<n_xb; j++) {
    if( sa[i] == sb[j] ) res[i] = i+1;
  }
}
return res;
'
cpp_whichin <- cxxfunction(signature(a="character",b="character"), cpp_whichin_src, plugin="Rcpp")

which.in_cpp <- function(char1, char2) {
  idx <- cpp_whichin(char1,char2)
  idx[idx!=0]
}

which.in_naive <- function(char1, char2) {
  which(char1 %in% char2)
}

which.in_CW <- function(char1, char2) {
  unlist(sapply(char2,function(x) which(x==char1)))
}

which.in_cpp(char1,char2)
which.in_naive(char1,char2)
which.in_CW(char1,char2)

**基准**

library(microbenchmark)
microbenchmark(
  which.in_cpp(char1,char2),
  which.in_naive(char1,char2),
  which.in_CW(char1,char2)
)

set.seed(1)
cmb <- apply(combn(letters,2), 2, paste,collapse="")
char1 <- sample( cmb, 100 )
char2 <- sample( cmb, 100 )

Unit: microseconds
                          expr     min      lq   median       uq      max
1   which.in_cpp(char1, char2) 114.890 120.023 126.6930 135.5630  537.011
2    which.in_CW(char1, char2) 697.505 725.826 766.4385 813.8615 8032.168
3 which.in_naive(char1, char2)  17.391  20.289  22.4545  25.4230   76.826

# Same as above, but with 3 letter combos and 1000 sampled

Unit: microseconds
                          expr       min        lq     median        uq       max
1   which.in_cpp(char1, char2)  8505.830  8715.598  8863.3130  8997.478  9796.288
2    which.in_CW(char1, char2) 23430.493 27987.393 28871.2340 30032.450 31926.546
3 which.in_naive(char1, char2)   129.904   135.736   158.1905   180.260  3821.785

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM