2011-11-02 24 views
6

¿Alguien sabe una forma ordenada/eficiente para reemplazar elementos diagonales en conjunto, similar al uso de diag(x) <- value para una matriz? En otras palabras, algo como esto:reemplazar elementos diagonales en una matriz

> m<-array(1:27,c(3,3,3)) 
> for(k in 1:3){ 
+ diag(m[,,k])<-5 
+ } 
> m 
, , 1 

    [,1] [,2] [,3] 
[1,] 5 4 7 
[2,] 2 5 8 
[3,] 3 6 5 

, , 2 

[,1] [,2] [,3] 
[1,] 5 13 16 
[2,] 11 5 17 
[3,] 12 15 5 

, , 3 

    [,1] [,2] [,3] 
[1,] 5 22 25 
[2,] 20 5 26 
[3,] 21 24 5 

pero sin el uso de un bucle (mis arreglos son bastante grande y esta manipulación ya estarán dentro de un bucle).

Muchas gracias.

Respuesta

6

Prueba esto:

with(expand.grid(a = 1:3, b = 1:3), replace(m, cbind(a, a, b), 5)) 

EDIT:

La pregunta hecha por aseado/eficiente, pero, por supuesto, los que no son la misma cosa. El único trazador de líneas aquí es compacto y sin bucles, pero si buscas velocidad, creo que encontrarás que el ciclo en la pregunta es en realidad la más rápida de todas las respuestas.

+0

+1 muy agradable. Es más rápido que mi código de función. –

+0

buen trabajo, ¡salud! – gjabel

5

Puede usar la siguiente función para eso, siempre que tenga solo 3 dimensiones en su matriz. Se puede generalizar a más dimensiones en base a este código, pero soy demasiado perezoso para hacer eso por ti ;-)

`arraydiag<-` <- function(x,value){ 
    dims <- dim(x) 
    id <- seq_len(dims[1]) + 
     dims[2]*(seq_len(dims[2])-1) 
    id <- outer(id,(seq_len(dims[3])-1)*prod(dims[1:2]),`+`) 
    x[id] <- value 
    dim(x) <- dims 
    x 
} 

Esto funciona como:

m<-array(1:36,c(3,3,4)) 
arraydiag(m)<-NA 
m 

Tenga en cuenta que, en contra de la diag() función, esta función no puede tratar con matrices que no son cuadrados. Puede ver el código fuente de diag() para averiguar cómo adaptar este código para que así sea.

+0

impresionante, funciona un placer! – gjabel

3
diagArr <- 
function (dim) 
{ 
    n <- dim[2] 
    if(dim[1] != n) stop("expecting first two dimensions to be equal") 
    d <- seq(1, n*n, by=n+1) 
    as.vector(outer(d, seq(0, by=n*n, length=prod(dim[-1:-2])), "+")) 
} 

m[diagArr(dim(m))] <- 5 

Esto está escrito con la intención de que funcione para dimensiones superiores a 3 pero no lo he probado en ese caso. Debería estar bien sin embargo.

+0

No crea una matriz diagonal en dims> 2. Crea múltiples n x n matriz diagonal. – papirrin

Cuestiones relacionadas