我需要找到向量中值的第二个非顺序出现的索引。
一些示例向量:
示例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 :(得分: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
答案 1 :(得分:3)
也许which
和diff
的组合可能有用:
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 :(得分:3)
这是一个只有R的实现,它比Rcpp快得多,虽然我们在向量中没有深入,所以我不知道这是否有意义。
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
以便从10,000个值而不是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
答案 3 :(得分: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
x
。s
开始构建一个序列x
。w==s=TRUE
是第一次出现时连续出现的那些事件,因此您希望返回w!=s
的第一个位置,即第一个位置不是第一个位置。答案 4 :(得分:2)
如果速度是这里的一个重要因素(并且,阅读原始帖子,似乎可能是这样),那么使用Rcpp的自定义解决方案可能比目前发布的任何纯R方法更快: / p>
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