Performance 求R中矩阵中整数向量索引的最快方法
在R中有以下问题(对于马尔可夫链)。假设有一个状态空间矩阵S,其中有行唯一的整数向量(状态)。我从这个矩阵中得到了一个向量s,我想确定对应于这个向量的行的索引。有两种解决方案:Performance 求R中矩阵中整数向量索引的最快方法,performance,r,vector,comparison,integer,Performance,R,Vector,Comparison,Integer,在R中有以下问题(对于马尔可夫链)。假设有一个状态空间矩阵S,其中有行唯一的整数向量(状态)。我从这个矩阵中得到了一个向量s,我想确定对应于这个向量的行的索引。有两种解决方案: 使用all.equal的解决方案,如: which(apply(S,1,function(x){ isTRUE(all.equal(s,x)) }) ) 将向量映射到唯一字符串,并使用此字符串标识它们: statecodes <- apply(S,1,function(x) paste(x,collapse="
all.equal
的解决方案,如:
which(apply(S,1,function(x){ isTRUE(all.equal(s,x)) }) )
statecodes <- apply(S,1,function(x) paste(x,collapse=" ") )
check.equal <- function(s) {
z <- which(statecodes == paste(s, collapse=" "))
return(z)
}
check.equal(s)
statecodes一种方法是其中(colSums(abs(t(S)-V))==0)
其中V
是您要查找的向量。获取每个状态的整数值的一种简单方法是将值转换为整数,然后将每列乘以右基
我的版本是makecheck2
;使用粘贴的版本是makecheck2
。我还修改了粘贴
版本以使用匹配
,因此它可以同时检查多个值。现在,两个版本都返回一个用于获取匹配项的函数
我的版本设置更快;0.065秒对1.552秒
N <- 5
I <- rep(10,N)
S <- as.matrix(expand.grid( lapply(1:N, function(i) { 0:I[i]}) ) )
system.time(f1 <- makecheck1(S))
# user system elapsed
# 1.547 0.000 1.552
system.time(f2 <- makecheck2(S))
# user system elapsed
# 0.063 0.000 0.065
两个版本的代码如下所示:
makecheck2 <- function(m) {
codes <- vector("list", length=ncol(m))
top <- vector("integer", length=ncol(m)+1)
top[1L] <- 1L
for(idx in 1:ncol(m)) {
codes[[idx]] <- unique(m[,idx])
top[idx+1L] <- top[idx]*length(codes[[idx]])
}
getcode <- function(x) {
out <- 0L
for(idx in 1:length(codes)) {
out <- out + top[idx]*match(x[,idx], codes[[idx]])
}
out
}
key <- getcode(m)
f <- function(x) {
if(!is.matrix(x)) {
x <- matrix(x, ncol=length(codes))
}
match(getcode(x), key)
}
rm(m) # perhaps there's a better way to remove these from the closure???
rm(idx)
f
}
makecheck1 <- function(m) {
n <- ncol(m)
statecodes <- apply(m,1,function(x) paste(x,collapse=" ") )
rm(m)
function(x) {
if(!is.matrix(x)) {
x <- matrix(x, ncol=n)
}
x <- apply(x, 1, paste, collapse=" ")
match(x, statecodes)
}
}
makecheck2不应将V
替换为矩阵(V,nrow,ncol,byrow=TRUE)
?谢谢提示。这是可行的,但似乎比将向量映射到唯一标识符(我的第二种方法)要慢。我想更多的是把一个向量转换成一个唯一的整数,但还不知道如何转换。这个比较需要反复进行,所以应该非常快,最好不要太占用内存。哇。您的解决方案大约快六倍。我想知道是否可以做得更快。对572392x6矩阵重复这两个步骤1000次。你的91.61秒,我的10.35秒。在这么大的矩阵上做所有的向量运算也会占用更多的内存。虽然我有一些想法,但这要求输出是数值而不是字符串。换句话说:我需要一个更好的映射。除非我遗漏了什么,否则,sum(abs(X-Y))==0
是必要的,但还不够。它本质上是一个弱校验和。如果希望X的每个元素都等于Y中对应的元素,则需要检查每个元素对。另一种方法是使用等效的FEC(前向纠错)编码方法来实现高概率的完全模式匹配。在第二种解决方案中,创建状态码所需的时间是否重要?也就是说,如果要对每个状态空间进行大量测试,那么这一部分只需执行一次,因此速度可能会较慢。但是,如果您只对每个状态空间执行一个测试,那么无论如何都需要对每个测试执行该测试。首选的解决方案可能会有所不同,这取决于您所处的条件。我会对状态空间矩阵中的每个向量重复执行这些比较,多次。因此,状态码向量的创建时间不是很重要。我先牺牲一点时间,以便以后生活得更好。也许我应该提一下。因此,我正在寻找一种可以使搜索尽可能快的方法,而不考虑预计算的时间。如果您的值是(小的)整数,并且可以很容易地使其变为非负,那么这可以加快速度,因为匹配
与唯一值匹配是不必要的。(如果可能需要小量以避免溢出)PPS。还有,请检查我的数学。我有一种预感,我应该先将匹配结果减去1,然后再乘以基数。另外,我认为这基本上就是@danas的评论中的链接。zuokas的答案就是这样做的。非常有用!我明天会更仔细地看一看,但这似乎正是我要找的东西。是的,这很好用!顺便说一句,对于单次比较,哪个
比匹配
快,但是对于多次比较,匹配
更快。为了进行多重比较,我必须重写我的代码。非常感谢你的帮助!
> set.seed(5)
> k <- lapply(0:4, function(idx) sample(1:nrow(S), 10^idx))
> s <- lapply(k, function(idx) S[idx,])
> t1 <- sapply(s, function(x) unname(system.time(for(i in 1:100) f1(x))[1]))
> t2 <- sapply(s, function(x) unname(system.time(for(i in 1:100) f2(x))[1]))
> data.frame(n=10^(0:4), time1=t1, time2=t2)
n time1 time2
1 1 0.761 1.512
2 10 0.772 1.523
3 100 0.857 1.552
4 1000 1.592 1.547
5 10000 9.651 1.848
makecheck2 <- function(m) {
codes <- vector("list", length=ncol(m))
top <- vector("integer", length=ncol(m)+1)
top[1L] <- 1L
for(idx in 1:ncol(m)) {
codes[[idx]] <- unique(m[,idx])
top[idx+1L] <- top[idx]*length(codes[[idx]])
}
getcode <- function(x) {
out <- 0L
for(idx in 1:length(codes)) {
out <- out + top[idx]*match(x[,idx], codes[[idx]])
}
out
}
key <- getcode(m)
f <- function(x) {
if(!is.matrix(x)) {
x <- matrix(x, ncol=length(codes))
}
match(getcode(x), key)
}
rm(m) # perhaps there's a better way to remove these from the closure???
rm(idx)
f
}
makecheck1 <- function(m) {
n <- ncol(m)
statecodes <- apply(m,1,function(x) paste(x,collapse=" ") )
rm(m)
function(x) {
if(!is.matrix(x)) {
x <- matrix(x, ncol=n)
}
x <- apply(x, 1, paste, collapse=" ")
match(x, statecodes)
}
}