2012-08-02 26 views
13

Debe una manera elegante de hacer esto, pero no puedo averiguar lo que:la creación de una matriz triangular

Las columnas son las probabilidades de 1 a 0 que van derecho

Las filas se probabilidades de 0 a 1 bajando

este código kludgy produce ver el resultado deseado (pero quiero hacerlo con una matriz mucho más grande que esto):

# Vector entries are rowname - colname, if >= 0 
# 
rb0 <- c(NA,NA,NA,NA,NA,NA,NA,NA,NA,NA, 0) 
rb1 <- c(NA,NA,NA,NA,NA,NA,NA,NA,NA, 0,.1) 
rb2 <- c(NA,NA,NA,NA,NA,NA,NA,NA, 0,.1,.2) 
rb3 <- c(NA,NA,NA,NA,NA,NA,NA, 0,.1,.2,.3) 
rb4 <- c(NA,NA,NA,NA,NA,NA, 0,.1,.2,.3,.4) 
rb5 <- c(NA,NA,NA,NA,NA, 0,.1,.2,.3,.4,.5) 
rb6 <- c(NA,NA,NA,NA, 0,.1,.2,.3,.4,.5,.6) 
rb7 <- c(NA,NA,NA, 0,.1,.2,.3,.4,.5,.6,.7) 
rb8 <- c(NA,NA, 0,.1,.2,.3,.4,.5,.6,.7,.8) 
rb9 <- c(NA, 0,.1,.2,.3,.4,.5,.6,.7,.8,.9) 
rb10 <- c(0,.1,.2,.3,.4,.5,.6,.7,.8,.9,1) 
indbias <- rbind(rb0,rb1,rb2,rb3,rb4,rb5,rb6,rb7,rb8,rb9,rb10) 
colnames(indbias) <- seq(1,0,by=-.1) 
rownames(indbias) <- seq(0,1,by=.1) 
indbias 

Gracias!

Respuesta

3
require(matlab) 
x=matrix(seq(0,1,.1),1) 
X=x[rep(1,c(11)),] 
X[upper.tri(X)]=NA 
X=t(X) 
for(a in 1:11){ 
    X[1:a,a]=rev(X[1:a,a]) 
} 
X=flipud(X) 
colnames(X) <- seq(1,0,by=-.1) 
rownames(X) <- seq(0,1,by=.1) 
+0

He corregido el formato de tu código, pero también te he votado negativamente porque el resultado no se parece en nada a lo que pidió el OP. :-( – GSee

+0

Gracias, GSee. Edité mi código para arreglarlo. – AGS

+0

gracias. Retiro de votos devueltos. Bienvenido a SO! – GSee

5

Una forma posible, usando mi actual biblioteca favorita:

library(plyr) 
daply(expand.grid(x=seq(1,0,-.1), y=seq(0,1,.1)), 
     .(y, x), with, 
     if (x+y >= 1) x+y-1 else NA) 

Esto da el siguiente resultado:

 x 
y  0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1 
    0 NA NA NA NA NA NA NA NA NA NA 0.0 
    0.1 NA NA NA NA NA NA NA NA NA 0.0 0.1 
    0.2 NA NA NA NA NA NA NA NA 0.0 0.1 0.2 
    0.3 NA NA NA NA NA NA NA 0.0 0.1 0.2 0.3 
    0.4 NA NA NA NA NA NA 0.0 0.1 0.2 0.3 0.4 
    0.5 NA NA NA NA NA 0.0 0.1 0.2 0.3 0.4 0.5 
    0.6 NA NA NA NA 0.0 0.1 0.2 0.3 0.4 0.5 0.6 
    0.7 NA NA NA 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 
    0.8 NA NA 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 
    0.9 NA 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 
    1 0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0 

La idea es que el expand.grid crea una trama de datos de todos los posibles valores de celda. También podría usar merge para esto. Luego aplica una función a cada uno de estos valores para calcular el contenido de la celda. Y haz que daply convierta esto en una buena matriz para ti, incluidos los nombres.

EDIT:
bien, que quería que las columnas etiquetadas en orden inverso. ddply los clasificará en orden ascendente. Así que trate de esto:

daply(expand.grid(x=seq(0,1,.1), y=seq(0,1,.1)), 
     .(y, x), with, 
     if (y-x >= 0) y-x else NA)[,11:1] 
 x 
y  1 0.9 0.8 0.7 0.6 0.5 0.4 0.3 0.2 0.1 0 
    0 NA NA NA NA NA NA NA NA NA NA 0.0 
    0.1 NA NA NA NA NA NA NA NA NA 0.0 0.1 
    0.2 NA NA NA NA NA NA NA NA 0.0 0.1 0.2 
    0.3 NA NA NA NA NA NA NA 0.0 0.1 0.2 0.3 
    0.4 NA NA NA NA NA NA 0.0 0.1 0.2 0.3 0.4 
    0.5 NA NA NA NA NA 0.0 0.1 0.2 0.3 0.4 0.5 
    0.6 NA NA NA NA 0.0 0.1 0.2 0.3 0.4 0.5 0.6 
    0.7 NA NA NA 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 
    0.8 NA NA 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 
    0.9 NA 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 
    1 0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0 
18
mat <- matrix(NA, 10,10) 
mat[row(mat)+col(mat) >=11] <- (row(mat)+col(mat) -11)[row(mat)+col(mat)>=11]/10 
mat 
     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] 
[1,] NA NA NA NA NA NA NA NA NA 0.0 
[2,] NA NA NA NA NA NA NA NA 0.0 0.1 
[3,] NA NA NA NA NA NA NA 0.0 0.1 0.2 
[4,] NA NA NA NA NA NA 0.0 0.1 0.2 0.3 
[5,] NA NA NA NA NA 0.0 0.1 0.2 0.3 0.4 
[6,] NA NA NA NA 0.0 0.1 0.2 0.3 0.4 0.5 
[7,] NA NA NA 0.0 0.1 0.2 0.3 0.4 0.5 0.6 
[8,] NA NA 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 
[9,] NA 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 
[10,] 0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 

Creo que esto será mucho más rápido que una solución plyr y se me ocurre pensar que es más fácil de comprender. Básicamente se establece una prueba para las entradas que se encuentran en la mano "triángulo" abajo a la derecha y luego divide los resultados de esa matriz de "prueba" bu 10. Usted puede mirar en el matriz de prueba con este código:

row(mat)+col(mat) -11 

Editar: pensé que era posible hacer la matriz una vez como sebastian-c ilustrado y luego hacer una prueba única para hacer la configuración NA podría ser más rápido (con un tercio de la cantidad de llamadas a row y col) pero parece ser solo un tercio tan rápido. Parece que las dos llamadas seq toman más tiempo que el extra:

mat <- round(outer(seq(-0.5, 0.5, 0.1), seq(-0.5, 0.5, 0.1), `+`), 1) 
is.na(mat) <- row(mat)+col(mat) <= 11 
mat 

Lo que encontrar otra solución basada en la poco conocida embed función:

mat <- embed(seq(-1,1, by=0.1), 11)[,11:1] 
is.na(mat) <- row(mat)+col(mat) <= 11 

pesar de que es 50% más rápido que el nuevo solución, es aún más lento que el original.

+0

(+1) Solución elegante y rápida. – chl

9

una solución ligeramente diferente, cercano en estilo a @ Dwin de:

Crear una matriz con el triángulo inferior adecuada (no creo que el redondeo es estrictamente necesario, pero por lo demás el error de punto flotante hace que se vea horrible):

mat <- round(outer(seq(-0.5, 0.5, 0.1), seq(-0.5, 0.5, 0.1), `+`), 1) 
mat 

     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] 
[1,] -1.0 -0.9 -0.8 -0.7 -0.6 -0.5 -0.4 -0.3 -0.2 -0.1 0.0 
[2,] -0.9 -0.8 -0.7 -0.6 -0.5 -0.4 -0.3 -0.2 -0.1 0.0 0.1 
[3,] -0.8 -0.7 -0.6 -0.5 -0.4 -0.3 -0.2 -0.1 0.0 0.1 0.2 
[4,] -0.7 -0.6 -0.5 -0.4 -0.3 -0.2 -0.1 0.0 0.1 0.2 0.3 
[5,] -0.6 -0.5 -0.4 -0.3 -0.2 -0.1 0.0 0.1 0.2 0.3 0.4 
[6,] -0.5 -0.4 -0.3 -0.2 -0.1 0.0 0.1 0.2 0.3 0.4 0.5 
[7,] -0.4 -0.3 -0.2 -0.1 0.0 0.1 0.2 0.3 0.4 0.5 0.6 
[8,] -0.3 -0.2 -0.1 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 
[9,] -0.2 -0.1 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 
[10,] -0.1 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 
[11,] 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0 

revertir la columnas

mat <- mat[,rev(seq.int(ncol(mat)))] 

Retire el triángulo superior:

mat[upper.tri(mat)] <- NA 

Re-invertir las columnas:

mat <- mat[,rev(seq_len(ncol(mat)))] 
mat 

     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] 
[1,] NA NA NA NA NA NA NA NA NA NA 0.0 
[2,] NA NA NA NA NA NA NA NA NA 0.0 0.1 
[3,] NA NA NA NA NA NA NA NA 0.0 0.1 0.2 
[4,] NA NA NA NA NA NA NA 0.0 0.1 0.2 0.3 
[5,] NA NA NA NA NA NA 0.0 0.1 0.2 0.3 0.4 
[6,] NA NA NA NA NA 0.0 0.1 0.2 0.3 0.4 0.5 
[7,] NA NA NA NA 0.0 0.1 0.2 0.3 0.4 0.5 0.6 
[8,] NA NA NA 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 
[9,] NA NA 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 
[10,] NA 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 
[11,] 0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0 

se puede cambiar el rownames desde allí.

EDITAR: Dado que hay tantas soluciones, le puede interesar ver cómo se comparan. Usando microbenchmark:

Unit: microseconds 
    expr  min   lq  median   uq  max 
1 AGS() 682.491 738.9370 838.0955 892.8815 4518.740 
2 DW() 23.244 27.1680 31.3930 34.8650 70.937 
3 MvG() 15469.664 15920.4820 17352.3215 17827.4380 18989.270 
4 SC() 118.629 131.4575 144.1360 157.7190 631.779 

@ solución de Dwin parece ser el más rápido por un margen bastante.

+0

Hacer ese punto de referencia es una buena idea. – MvG

Cuestiones relacionadas