我有两个向量,A
和B
。对于A
中的每个元素,我想找到B
中第一个元素的索引,该索引更大且索引更高。 A
和B
的长度相同。
所以对于载体:
A <- c(10, 5, 3, 4, 7)
B <- c(4, 8, 11, 1, 5)
我想要一个结果向量:
R <- c(3, 3, 5, 5, NA)
当然我可以使用两个循环来完成它,但它非常慢,并且当索引很重要时,我不知道如何在这种情况下使用apply()。我的数据集具有长度为20000的向量,因此在这种情况下速度非常重要。
一些奖励问题:
如果我有一系列数字(例如seq = 2:10
),我想找到B
中第一个数字高于+ s的每个A和每一个seq。
与问题1)相似,但我想知道第一个更大的值和第一个更低的值,并创建一个矩阵,它存储哪个是第一个。例如,我有 a A
, 10来自seq 。我想找到B
的第一个值,它高于 a + 10 ,或低于 a-10 ,然后将其存储在&#39; s指数和价值。
答案 0 :(得分:6)
sapply(sapply(seq_along(a),function(x) which(b[-seq(x)]>a[x])+x),"[",1)
[1] 3 3 5 5 NA
答案 1 :(得分:6)
这是一个很好的例子,说明当sapply效率低于循环时。 虽然sapply确实使代码看起来更整洁,但你需要为时间付出代价。
相反,你可以在一个漂亮,整洁的函数中将for循环包含在for循环中。
以下是基准比较嵌套应用循环与嵌套for-while循环(以及混合应用while循环,以获得良好衡量标准)。 更新:添加了评论中提到的vapply..match..
。比sapply更快,但仍然比while循环慢得多。
test elapsed relative
1 for.while 0.069 1.000
2 sapply.while 0.080 1.159
3 vapply.match 0.101 1.464
4 nested.sapply 0.104 1.507
请注意,您将保存了三分之一;当您开始将序列添加到A时,节省的费用可能会更大。
如果你把这一切都包含在一个很好的函数中,很容易将一个seq添加到A
# Sample data
A <- c(10, 5, 3, 4, 7, 100, 2)
B <- c(4, 8, 11, 1, 5, 18, 20)
# Sample sequence
S <- seq(1, 12, 3)
# marix with all index values (with names cleaned up)
indexesOfB <- t(sapply(S, function(s) findIndx(A+s, B)))
dimnames(indexesOfB) <- list(S, A)
最后,如果您想要找到B 小于 A的值,只需在函数中交换操作。
(你可以在函数中包含一个if子句,只使用一个函数。我发现它更有效率
有两个独立的功能)
findIndx.gt(A, B) # [1] 3 3 5 5 6 NA 8 NA NA
findIndx.lt(A, B) # [1] 2 4 4 NA 8 7 NA NA NA
然后你可以把它包装在一个漂亮的pacakge
中rangeFindIndx(A, B, S)
# A S indxB.gt indxB.lt
# 10 1 3 2
# 5 1 3 4
# 3 1 5 4
# 4 1 5 NA
# 7 1 6 NA
# 100 1 NA NA
# 2 1 NA NA
# 10 4 6 4
# 5 4 3 4
# ...
<小时/>
(请注意,它们取决于reshape2
)
rangeFindIndx <- function(A, B, S) {
# For each s in S, and for each a in A,
# find the first value of B, which is higher than a+s, or lower than a-s
require(reshape2)
# Create gt & lt matricies; add dimnames for melting function
indexesOfB.gt <- sapply(S, function(s) findIndx.gt(A+s, B))
indexesOfB.lt <- sapply(S, function(s) findIndx.lt(A-s, B))
dimnames(indexesOfB.gt) <- dimnames(indexesOfB.gt) <- list(A, S)
# melt the matricies and combine into one
gtltMatrix <- cbind(melt(indexesOfB.gt), melt(indexesOfB.lt)$value)
# clean up their names
names(gtltMatrix) <- c("A", "S", "indxB.gt", "indxB.lt")
return(gtltMatrix)
}
findIndx.gt <- function(A, B) {
lng <- length(A)
ret <- integer(0)
b <- NULL
for (j in seq(lng-1)) {
i <- j + 1
while (i <= lng && ((b <- B[[i]]) < A[[j]]) ) {
i <- i + 1
}
ret <- c(ret, ifelse(i<lng, i, NA))
}
c(ret, NA)
}
findIndx.lt <- function(A, B) {
lng <- length(A)
ret <- integer(0)
b <- NULL
for (j in seq(lng-1)) {
i <- j + 1
while (i <= lng && ((b <- B[[i]]) > A[[j]]) ) { # this line contains the only difference from findIndx.gt
i <- i + 1
}
ret <- c(ret, ifelse(i<lng, i, NA))
}
c(ret, NA)
}