我有类似的任务
n <- 5
set.seed(11)
X <- rnorm(n)
X.sort <- {}
for(i in 1:n){
X.sort <- sort.int(c(X.sort, X[i]), decreasing = TRUE)
print(X.sort) # actually, other computations with X.sort
}
产生类似的输出
[1] -0.5910311
[1] 0.02659437 -0.59103110
[1] 0.02659437 -0.59103110 -1.51655310
[1] 0.02659437 -0.59103110 -1.36265335 -1.51655310
[1] 1.17848916 0.02659437 -0.59103110 -1.36265335 -1.51655310
当矢量已被排序(除了要插入的新条目X.sort
除外)时,在循环的每一轮中对X[i]
进行“重新排序”的效率都不高。
我尝试过“告诉” R在何处插入元素
library(R.utils)
X.sort <- {}
for(i in 1:n){
pos <- match(F, X.sort>X[i])
if(is.na(pos)){
X.sort <- c(X.sort,X[i])
} else {
X.sort <- insert(X.sort, pos, X[i])
}
print(X.sort)
}
但是在基准测试时不会产生任何收益。
是否有明显的改进,还是R已经有效地利用了X.sort
被排序的知识?
编辑:
基准测试表明[但还请考虑以下问题]接受的答案最快(至少在n
接近1000时),而且似乎也适用于大型n
,并且成为最简单的一个。
library(R.utils)
library(microbenchmark)
n <- 600
set.seed(11)
X <- rnorm(n)
sorted_insert <- function(x, y) {
c(x[x >= y], y, x[x < y])
}
recursive_fun <- function(ans=list(NULL), vec, i=1) {
if (i > length(vec)) {
tail(ans, -1)
} else {
ans <- c(ans, list(sorted_insert(ans[[i]], vec[i])))
recursive_fun(ans=ans, vec, i=i+1)
}
}
microbenchmark(
{
X.sort <- {}
for(i in 1:n){
X.sort <- sort.int(c(X.sort, X[i]), decreasing = TRUE)
}
},{
X.sort <- {}
for(i in 1:n){
pos <- match(F, X.sort>X[i])
if(is.na(pos)){
X.sort <- c(X.sort,X[i])
} else {
X.sort <- insert(X.sort, pos, X[i])
}
}
},{
X.sort <- {X[1]}
for(i in 2:n){
X.sort <- append(X.sort, X[i], after = sum(X.sort > X[i]))
}
},{
lapply(seq_along(X), function(a) {sort(X[seq_len(a)], decreasing = T)})
},{
lapply(1:length(X), function(i) sort(X[1:i], decreasing = T))
},
{
recursive_fun(vec=X)
},
times=50
)
结果:
min lq mean median uq max neval
21.308012 22.264314 24.065012 22.798643 26.381362 34.629395 50
19.554413 20.334643 21.875769 20.617807 24.085896 30.625841 50
4.497919 4.804550 5.380192 4.912923 5.114310 13.522485 50
23.540616 24.105807 25.311692 24.335780 24.985024 30.348792 50
23.251905 24.067122 25.722031 24.745380 27.986197 30.010018 50
3.928746 4.096568 4.358911 4.258701 4.390684 9.106202 50
答案 0 :(得分:2)
代码中的瓶颈实际上是print
语句。
这是另一种速度快大约5倍的方法(如果不需要打印):
n <- 10000
set.seed(11)
X <- rnorm(n)
X.sort <- {X[1]}
for(i in 2:n){
X.sort <- append(X.sort, X[i], after = sum(X.sort > X[i]))
}
答案 1 :(得分:1)
您可以尝试这种递归方法
working 函数是sorted_insert
,它将new元素插入元素>=
new-element,vec[vec >= y]
和{{ 1}}新元素<
。假定向量总是被排序的(在这种情况下是真的)。
vec[vec < y]
sorted_insert <- function(x, y) {
c(x[x >= y], y, x[x < y])
}
由sorted_function
递归调用。如果计数器recursive_fun
为i
向量的长度(即未遍历整个未分类输入向量),则它将使用先前的分类答案{ {1}}作为输入向量,<=
作为要插入的新元素。也就是说,每次迭代中的排序向量都是使用前一次迭代中的排序向量和未排序输入向量中的新元素建立的。抱歉,请尽我所能解释。
sorted_function
使用给定的示例
ans[[i]]
一个更大的例子
vec[i]
如果您的unsorted-input-vector很大,就会出现问题
recursive_fun <- function(ans=list(NULL), vec, i=1) {
if (i > length(vec)) {
tail(ans, -1)
} else {
ans <- c(ans, list(sorted_insert(ans[[i]], vec[i])))
recursive_fun(ans=ans, vec, i=i+1)
}
}
请注意,如果您不想要在每次迭代中收集结果,则可以使用n <- 5
set.seed(11)
X <- rnorm(n)
recursive_fun(vec=X)
,它应该很快。
答案 2 :(得分:0)
这里是lapply
的一种方式-
n <- 5
set.seed(11)
x <- rnorm(n)
lapply(seq_along(x), function(a) {
sort(x[seq_len(a)], decreasing = T)
})
[[1]]
[1] -0.5910311
[[2]]
[1] 0.02659437 -0.59103110
[[3]]
[1] 0.02659437 -0.59103110 -1.51655310
[[4]]
[1] 0.02659437 -0.59103110 -1.36265335 -1.51655310
[[5]]
[1] 1.17848916 0.02659437 -0.59103110 -1.36265335 -1.51655310
为了提高性能,您应该考虑将{cy1b}与Reduce
一起使用。请参阅下面的基准-
n <- 600
set.seed(11)
x <- rnorm(n)
r_sort <- function(x, y) {
append(x, y, after = sum(x > y))
}
microbenchmark(
lapply = lapply(seq_along(x), function(a) {
sort(x[seq_len(a)], decreasing = T)
}),
forloop = {
x.sort <- x[1]
for(i in 2:n){
x.sort <- append(x.sort, x[i], after = sum(x.sort > x[i]))
}
},
Reduce = Reduce(r_sort, as.list(x), accumulate = T), # only if you want intermediate results
Reduce2 = Reduce(r_sort, as.list(x)),
times = 50
)
Unit: milliseconds
expr min lq mean median uq max neval
lapply 35.069533 36.318154 45.302362 37.870738 41.959249 203.45682 50
forloop 8.366112 8.743501 11.196852 9.128391 11.800904 30.76272 50
Reduce 4.574459 4.861448 7.418195 5.332593 11.076522 22.40293 50
Reduce2 4.556300 4.754075 6.918486 5.161860 9.563809 14.41776 50