我需要在 R 中执行涉及大量一般线性回归的离散事件模拟,因此需要将大量 R 对象一一附加到列表或数组中。现在一切都已经实现并且模拟器运行了。但是,我意识到整个过程的性能瓶颈实际上是在列表追加(模拟6000个事件大约需要15分钟)。我注意到当 R 列表、向量或数组中的对象数量变大时,插入变得非常慢。我需要一个可重用的列表数据结构,因为它在模拟代码的许多部分中一次又一次地使用。这是我用 R 编写的简单 ArrayList 的实现:
ArrayListX = setRefClass(
Class = "ArrayListX",
fields = list(
ol = "array",
len = "integer",
cap = "integer",
expandNum = "integer"),
methods = list(
initialize = function(){
len <<- 0L
expandNum <<- 100000L
#TODO: The preallocation here made the performance worse.
ol <<- array(dim = expandNum)
cap <<- expandNum
},
expand = function(){
ol <<- c(ol, array(list(), dim = expandNum))
cap <<- cap + expandNum
},
get = function(i){
return(ol[i])
},
remove = function(i){
ol[i] <<- NULL
len <<- len - 1L
},
add = function(obj){
if(cap <= len)
{
expand()
}
len <<- len + 1L
ol[len] <<- obj
return(len)
},
size = function(){
return(len)
},
set = function(i, obj){
ol[i] <<- obj
},
insert = function(before, obj){
if(before < 1 || before > len + 1)
throw(paste("Subscript out of bound. before = ", before))
if(len == 0)
{
ol[1] <<- obj
} else
{
head = ol[1:before - 1]
head[before] = obj
{
if(before <= len)
ol <<- c(head, ol[before:len])
else
ol <<- head
}
}
len <<- len + 1L
}
)
)
请注意,我尝试初始化列表并预分配一定数量的行,这也没有提高性能,实际上它甚至比没有预分配还要慢。(这可能是因为我使用了引用类。根据我的经验,在不使用引用类时,预分配通常会提高 R 中的性能)这就是为什么我考虑使用 Java ArrayList 作为列表的后端数据结构的原因。我尝试了 rJava。
ArrayListJ = setRefClass(
Class = "ArrayListJ",
contains = "ArrayList",
fields = list(
jal = "ANY"),
methods = list(
initialize = function(){
jal <<- .jnew("java.util.ArrayList")
},
get = function(i){
rObj = .jcall(jal, returnSig="Ljava/lang/Object;", method = "get", as.integer(i))
return(rObj)
},
remove = function(i){
},
add = function(obj){
jRef = toJava(x = obj, engine = NULL)
.jcall(obj = jal, returnSig = "Z", method = "add", .jcast(jRef, new.class = "java/lang/Object"))
},
size = function(){
s = .jcall(obj = jal, returnSig = "I", method = "size")
return (s)
},
set = function(i, obj){
#Not implemented yet.
},
insert = function(before, obj){
#Not implemented yet.
}
)
)
我现在正在努力使用“get”功能,因为我无法让它工作。它总是返回一个我不能在 R 中使用的 REXPReference 对象。我希望它返回的实际上是添加到 ArrayListJ 的原始 R 对象 obj。它必须是最初引用的对象,因为插入的 R 对象在插入 ArrayListJ 后可能已被其他逻辑更新。有人可以帮我实现 ArrayListX 或 ArrayListJ 吗?它基本上需要能够以恒定的时间将大量的R referenceclasses对象一个一个地追加到一个列表中(当列表变大时性能不应该变慢)。对于 ArrayListJ 实现,如何使用“get”方法取回最初引用的 R 对象?谢谢。