我正在尝试编写一个R函数来创建一个名为 Ui 的特殊矩阵(第5页):http://joshuachan.org/papers/Chan-Jeliazkov-2009.pdf
到目前为止,我已经开发了这个函数,我怀疑它可以改进(即效率更高):
create_Uj <- function(uj) {
q <- length(uj)
if (q == 1) return(0)
nr <- q
nc <- q*(q-1)/2
Uj <- matrix(0, nrow = nr, ncol = nc)
for (kk in 2:nr) {
uj_sub <- uj[1:(kk-1)]
Uj[kk, 1:(kk*(kk-1)/2)] <- c(rep(0, (kk-1)*(kk-2)/2), uj[1:(kk-1)])
}
-Uj
}
create_Uj(1:4)
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 0 0 0 0 0 0
[2,] -1 0 0 0 0 0
[3,] 0 -1 -2 0 0 0
[4,] 0 0 0 -1 -2 -3
有更好的方法来编码吗?
注意:我在论文中使用下标 j 而不是 i
答案 0 :(得分:2)
通过避免创建rep(0, (kk-1)*(kk-2)/2)
,您可以获得不错的加速。事实上,删除此步骤会显着加快速度,这让我觉得如果不使用Rcpp
create_Uj2 <- function(uj) {
q <- length(uj)
if (q == 1) return(0)
nr <- q
nc <- q*(q-1)/2
Uj <- matrix(0, nrow = nr, ncol = nc)
for (kk in 2:nr) {
Uj[kk, ((kk-1)*(kk-2)/2 + 1):(kk*(kk-1)/2)] <- uj[1:(kk-1)]
}
-Uj
}
all.equal(create_Uj2(1:400), create_Uj(1:400))
# [1] TRUE
microbenchmark(
create_Uj2(1:400),
create_Uj(1:400),
times = 10,
unit = 'relative'
)
# Unit: relative
# expr min lq mean median uq max neval
# create_Uj2(1:400) 1.000000 1.000000 1.000000 1.000000 1.000000 1.0000000 10
# create_Uj(1:400) 2.070708 1.847242 1.529658 2.028489 1.496275 0.9441935 10
答案 1 :(得分:2)
也可以使用嵌套for循环来编写函数:
create_Uj3 = function(uj){
nr <- length(uj)
if (nr == 1){
return(0)
}
nc <- nr*(nr-1)/2
Uj <- matrix(0, nrow = nr, ncol = nc)
for (kk in 2:nr) {
for (ll in 1:(kk-1)){
Uj[kk, ((kk-1)*(kk-2)/2) + ll] <- uj[ll]
}
}
return(-Uj)
}
Rcpp等价物:
library(Rcpp)
cppFunction('NumericMatrix create_Uj_rcpp(NumericVector uj) {
const int nr = uj.size();
if(nr == 1){
return 0;
}
const int nc = (nr*(nr-1))/2;
NumericMatrix Uj = NumericMatrix(nr, nc);
for(int i = 1; i < nr; i++) {
for(int j = 0; j <= (i - 1); j++){
Uj(i,(i*(i-1)/2) + j) = -uj[j];
}
}
return Uj;
}')
<强>基准:强>
> identical(create_Uj(1:300), create_Uj2(1:300))
[1] TRUE
> identical(create_Uj(1:300), create_Uj3(1:300))
[1] TRUE
> identical(create_Uj(1:300), create_Uj_rcpp(1:300))
[1] TRUE
library(microbenchmark)
microbenchmark(create_Uj(1:300),
create_Uj2(1:300),
create_Uj3(1:300),
create_Uj_rcpp(1:300),
unit = 'relative')
Unit: relative
expr min lq mean median uq max neval
create_Uj(1:300) 6.299113 6.874493 4.351439 5.128115 4.059644 2.105598 100
create_Uj2(1:300) 2.859025 3.827864 2.524505 2.873346 2.233600 1.618327 100
create_Uj3(1:300) 3.078410 4.111635 2.552434 3.109537 2.259824 1.418917 100
create_Uj_rcpp(1:300) 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 100
create_Uj_rcpp
在速度方面获胜。请注意,Base R嵌套for循环方法(create_Uj3
)比Ryan的解决方案(create_Uj2
)慢一点,但仍比OP的函数(create_Uj
)快得多。