2011-04-19 16 views
5

tengo una matriz con diagonales iguales a cero y fuera de diagonales todos iguales a uno (la inversa de una matriz de identidad):Crear una matriz de similitud de números enteros, usando R

mat1 <- matrix(c(0,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0), 5, 5) 

También tengo un vector que es siempre la misma longitud que los atenúa de la matriz y siempre comienza en cero:

vec1 <- c(0,1,2,3,4) 

el uso de estos dos objetos que desea crear una matriz que tiene este aspecto:

mat2 <- matrix(c(0,1,2,3,4,1,0,1,2,3,2,1,0,1,2,3,2,1,0,1,4,3,2,1,0), 5, 5) 

    [,1] [,2] [,3] [,4] [,5] 
[1,] 0 1 2 3 4 
[2,] 1 0 1 2 3 
[3,] 2 1 0 1 2 
[4,] 3 2 1 0 1 
[5,] 4 3 2 1 0 

Quiero una operación que se generalice de modo que si tengo una matriz de dims 9 por 9, por ejemplo, y un vector de 0: 8 puedo lograr el resultado equivalente. ¿Alguna idea de cómo abordar esto?

Respuesta

6

Como vec1 comienza con un cero, entonces se puede hacer:

MakeMatrix <- function(x){ 
    n <- length(x) 
    id <- abs(rep(1:n,n)-rep(1:n,each=n)) + 1 
    matrix(x[id],ncol=n) 
} 

MakeMatrix(vec1) 

Así que no hay necesidad de tomar el mat1 en la entrada, ya que uno es en realidad redundante. Puedes simplemente construir la matriz dentro de la función.

El truco está en proporcionar una secuencia de valores de identificación para seleccionar del vector, y luego transformar todo en una matriz.


Editar: Si sólo va a utilizar secuencias, se puede hacer así:

MakeMatrix <- function(n){ 
    id <- abs(rep(1:n,n)-rep(1:n,each=n)) 
    matrix(id,ncol=n) 
} 

MakeMatrix(7) 
+1

+1 Buen uso de representante. – Andrie

+0

Me gusta la simplicidad de este enfoque. ¡Muchas gracias! – Steve

6

La siguiente solución utiliza upper.tri y lower.tri para aislar la matriz triangular superior e inferior. Además, utiliza sequence para crear la secuencia vectorial deseada.

n <- 9 
vec <- (1:n)-1 
m <- matrix(0, n, n) 
m[lower.tri(m, diag=TRUE)] <- vec[sequence(n:1)] #### Edit 
m <- t(m) 
m[lower.tri(m, diag=TRUE)] <- vec[sequence(n:1)] #### Edit 
m 

     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] 
[1,] 0 1 2 3 4 5 6 7 8 
[2,] 1 0 1 2 3 4 5 6 7 
[3,] 2 1 0 1 2 3 4 5 6 
[4,] 3 2 1 0 1 2 3 4 5 
[5,] 4 3 2 1 0 1 2 3 4 
[6,] 5 4 3 2 1 0 1 2 3 
[7,] 6 5 4 3 2 1 0 1 2 
[8,] 7 6 5 4 3 2 1 0 1 
[9,] 8 7 6 5 4 3 2 1 0 
+0

+1 para secuencia y lower.tri(). agradable, aunque debería usar m como índices para seleccionar de un vector de entrada. Nada garantiza que OP use una secuencia como vec1 ... –

+0

@Joris Buen comentario. Ahora he hecho una pequeña modificación: usar sequence() como índice para un vector suministrado. Esto debería funcionar ahora para cualquier n y vec. – Andrie

1

¿Qué tal:

genMat <- function(n){ 
    mat <- outer(1:n,1:n,"-")%%n 
    tmp <- mat[lower.tri(mat)] 
    mat <- t(mat) 
    mat[lower.tri(mat)] <- tmp 
    mat 
} 

> genMat(5) 
    [,1] [,2] [,3] [,4] [,5] 
[1,] 0 1 2 3 4 
[2,] 1 0 1 2 3 
[3,] 2 1 0 1 2 
[4,] 3 2 1 0 1 
[5,] 4 3 2 1 0 

Editar

Para arbitrario vec1:

genMat2 <- function(vec){ 
    n <- length(vec) 
    mat <- outer(1:n,1:n,"-")%%n 
    tmp <- mat[lower.tri(mat)] 
    mat <- t(mat) 
    mat[lower.tri(mat)] <- tmp 
    matrix(vec[mat+1],n,n) 
} 

> genMat2(c(0,2,4,3,9)) 
    [,1] [,2] [,3] [,4] [,5] 
[1,] 0 2 4 3 9 
[2,] 2 0 2 4 3 
[3,] 4 2 0 2 4 
[4,] 3 4 2 0 2 
[5,] 9 3 4 2 0 

Editar 2 De hecho, no hay necesidad de usar el módulo y luego jugar con la matriz, abs funcionará bien para hacer que la definición matriz original una 1-liner:

abs(outer(1:n,1:n,"-")) 

Así,

genMat <- function(n){ 
    abs(outer(1:n,1:n,"-")) 
} 

y

genMat2 <- function(vec){ 
    n <- length(vec) 
    matrix(vec[abs(outer(1:n,1:n,"-"))+1],n,n) 
} 
Cuestiones relacionadas