给定向量和 0 沿反对角线排列生成 5x5 矩阵
Generating 5x5 matrix given a vector and 0's lined anti-diagonally
给定仅以下向量:
v <- c(2, 4, 6, 8)
需要以下矩阵,其中行方向交替从右到左和从左到右(通过从上到下遍历矩阵)并且反对角线设置为零。
8 6 4 2 0
2 4 6 0 8
8 6 0 4 2
2 0 4 6 8
0 8 6 4 2
如何在 R 中有效地实现这一点?
这个怎么样?
v <- c(2, 4, 6, 8)
首先创建一个交替方向为v
的矩阵。因为矩阵是按列填充的,所以我们最后必须转置。
m <- matrix(0, length(v), length(v) + 1)
m[, c(FALSE, TRUE)] <- rev(v)
m[, c(TRUE, FALSE)] <- v
m <- t(m)
现在通过填充上下三角形然后反转列来创建零反对角线:
m1 <- matrix(0, length(v) + 1, length(v) + 1)
m1[upper.tri(m1)] <- m[upper.tri(m, TRUE)]
m1[lower.tri(m1)] <- m[lower.tri(m)]
m1[, rev(seq_len(ncol(m1)))]
# [,1] [,2] [,3] [,4] [,5]
#[1,] 8 6 4 2 0
#[2,] 2 4 6 0 8
#[3,] 8 6 0 4 2
#[4,] 2 0 4 6 8
#[5,] 0 8 6 4 2
我希望这对于更大尺寸的向量来说是一个有效的解决方案。对于小向量,基于循环的解决方案可能更快。
这里有一个更好的方法来解决这个问题:
rv <- rev(v)
f <- function(vec, pos){z<-rep(NA,length(vec)+1);z[pos]<-0;z[is.na(z)]<-vec;z;}
t(sapply(5:1, function(x) {if (x%%2==1) f(rv,x) else f(v,x)}))
# [,1] [,2] [,3] [,4] [,5]
# [1,] 8 6 4 2 0
# [2,] 2 4 6 0 8
# [3,] 8 6 0 4 2
# [4,] 2 0 4 6 8
# [5,] 0 8 6 4 2
函数 f
,将 0
插入 vec
的指定位置 pos
。
基准测试
library(microbenchmark)
v <- c(2, 4, 6, 8)
rv <- rev(v)
f <- function(vec, pos){z<-rep(NA,length(vec)+1);z[pos]<-0;z[is.na(z)]<-vec;z;}
f_m0h3n <- function(v){t(sapply(5:1, function(x) {if (x%%2==1) f(rv,x) else f(v,x)}))}
f_Roland <- function(v){
m <- matrix(0, length(v), length(v) + 1)
m[, c(FALSE, TRUE)] <- rev(v)
m[, c(TRUE, FALSE)] <- v
m <- t(m)
m1 <- matrix(0, length(v) + 1, length(v) + 1)
m1[upper.tri(m1)] <- m[upper.tri(m, TRUE)]
m1[lower.tri(m1)] <- m[lower.tri(m)]
m1[, rev(seq_len(ncol(m1)))]
}
all(f_m0h3n(v)==f_Roland(v))
# [1] TRUE
microbenchmark(f_m0h3n(v), f_Roland(v))
# Unit: microseconds
# expr min lq mean median uq max neval
# f_m0h3n(v) 106.931 109.4975 115.1818 112.064 119.7625 180.927 100
# f_Roland(v) 114.202 116.3410 128.5183 119.763 126.8210 430.290 100
给定仅以下向量:
v <- c(2, 4, 6, 8)
需要以下矩阵,其中行方向交替从右到左和从左到右(通过从上到下遍历矩阵)并且反对角线设置为零。
8 6 4 2 0
2 4 6 0 8
8 6 0 4 2
2 0 4 6 8
0 8 6 4 2
如何在 R 中有效地实现这一点?
这个怎么样?
v <- c(2, 4, 6, 8)
首先创建一个交替方向为v
的矩阵。因为矩阵是按列填充的,所以我们最后必须转置。
m <- matrix(0, length(v), length(v) + 1)
m[, c(FALSE, TRUE)] <- rev(v)
m[, c(TRUE, FALSE)] <- v
m <- t(m)
现在通过填充上下三角形然后反转列来创建零反对角线:
m1 <- matrix(0, length(v) + 1, length(v) + 1)
m1[upper.tri(m1)] <- m[upper.tri(m, TRUE)]
m1[lower.tri(m1)] <- m[lower.tri(m)]
m1[, rev(seq_len(ncol(m1)))]
# [,1] [,2] [,3] [,4] [,5]
#[1,] 8 6 4 2 0
#[2,] 2 4 6 0 8
#[3,] 8 6 0 4 2
#[4,] 2 0 4 6 8
#[5,] 0 8 6 4 2
我希望这对于更大尺寸的向量来说是一个有效的解决方案。对于小向量,基于循环的解决方案可能更快。
这里有一个更好的方法来解决这个问题:
rv <- rev(v)
f <- function(vec, pos){z<-rep(NA,length(vec)+1);z[pos]<-0;z[is.na(z)]<-vec;z;}
t(sapply(5:1, function(x) {if (x%%2==1) f(rv,x) else f(v,x)}))
# [,1] [,2] [,3] [,4] [,5]
# [1,] 8 6 4 2 0
# [2,] 2 4 6 0 8
# [3,] 8 6 0 4 2
# [4,] 2 0 4 6 8
# [5,] 0 8 6 4 2
函数 f
,将 0
插入 vec
的指定位置 pos
。
基准测试
library(microbenchmark)
v <- c(2, 4, 6, 8)
rv <- rev(v)
f <- function(vec, pos){z<-rep(NA,length(vec)+1);z[pos]<-0;z[is.na(z)]<-vec;z;}
f_m0h3n <- function(v){t(sapply(5:1, function(x) {if (x%%2==1) f(rv,x) else f(v,x)}))}
f_Roland <- function(v){
m <- matrix(0, length(v), length(v) + 1)
m[, c(FALSE, TRUE)] <- rev(v)
m[, c(TRUE, FALSE)] <- v
m <- t(m)
m1 <- matrix(0, length(v) + 1, length(v) + 1)
m1[upper.tri(m1)] <- m[upper.tri(m, TRUE)]
m1[lower.tri(m1)] <- m[lower.tri(m)]
m1[, rev(seq_len(ncol(m1)))]
}
all(f_m0h3n(v)==f_Roland(v))
# [1] TRUE
microbenchmark(f_m0h3n(v), f_Roland(v))
# Unit: microseconds
# expr min lq mean median uq max neval
# f_m0h3n(v) 106.931 109.4975 115.1818 112.064 119.7625 180.927 100
# f_Roland(v) 114.202 116.3410 128.5183 119.763 126.8210 430.290 100