Ecco un'opzione con lower.tri
e t
di trasporre il risultato:
k <- 1:15
m <- matrix(0, 5,5)
m[lower.tri(m, diag = TRUE)] <- k
m <- t(m)
m
# [,1] [,2] [,3] [,4] [,5]
#[1,] 1 2 3 4 5
#[2,] 0 6 7 8 9
#[3,] 0 0 10 11 12
#[4,] 0 0 0 13 14
#[5,] 0 0 0 0 15
microbenchmark
Dato che c'era un po 'di confusione con riferimento di Giuseppe, ecco un altro uno. Ho testato le tre soluzioni per matrici di dimensioni 10 * 10; 100 * 100; 1000 * 1000; 10000 * 10000.
Risultati:
A quanto pare, la performance dipende fortemente dalla dimensione della matrice. Per le matrici di grandi dimensioni, la risposta di Joseph è più veloce, mentre per le matrici più piccole, la mia è stata l'approccio più veloce. Si noti che ciò non tiene conto dell'efficienza della memoria.
riferimento riproducibile:
Joseph <- function(k, n) {
y <- 1L
t <- rep(0L,n)
j <- c(y, sapply(1:(n-1L), function(x) y <<- y+(n+1L)-x))
t(vapply(1:n, function(x) c(rep(0L,x-1L),k[j[x]:(j[x]+n-x)]), t, USE.NAMES = FALSE))
}
Frank <- function(k, n) {
m = matrix(0L, n, n)
m[ which(lower.tri(m, diag=TRUE), arr.ind=TRUE)[, 2:1] ] = k
m
}
docendo <- function(k,n) {
m <- matrix(0L, n, n)
m[lower.tri(m, diag = TRUE)] <- k
t(m)
}
library(microbenchmark)
library(data.table)
library(ggplot2)
n <- c(10L, 100L, 1000L, 10000L)
k <- lapply(n, function(x) seq.int((x^2 + x)/2))
b <- lapply(seq_along(n), function(i) {
bm <- microbenchmark(Joseph(k[[i]], n[i]), Frank(k[[i]], n[i]), docendo(k[[i]], n[i]), times = 10L)
bm$n <- n[i]
bm
})
b1 <- rbindlist(b)
ggplot(b1, aes(expr, time)) +
geom_violin() +
facet_wrap(~ n, scales = "free_y") +
ggtitle("Benchmark for n = c(10L, 100L, 1000L, 10000L)")
Controllo parità di risultati:
all.equal(Joseph(k[[1]], n[1]), Frank(k[[1]], n[1]))
#[1] TRUE
all.equal(Joseph(k[[1]], n[1]), docendo(k[[1]], n[1]))
#[1] TRUE
Nota: non ho incluso l'approccio di George nel confronto dal momento che, a giudicare dai risultati di Giuseppe , sembra essere molto più lento. Quindi tutti gli approcci comparati nel mio benchmark sono scritti solo nella base R.
Nota: '(n^2 - n)/2 + n' è uguale a' sum (seq (n)) '. Bella risposta! –