vacio - Los valores de índice de una matriz utilizando fila, col indicies
tablas en r (4)
Aquí hay una línea usando las operaciones de fila de Apply
> dat <- as.data.frame(matrix(rep(seq(4),4),ncol=2))
> colnames(dat) <- c(''I'',''J'')
> dat
I J
1 1 1
2 2 2
3 3 3
4 4 4
5 1 1
6 2 2
7 3 3
8 4 4
> mat <- matrix(seq(16),ncol=4)
> mat
[,1] [,2] [,3] [,4]
[1,] 1 5 9 13
[2,] 2 6 10 14
[3,] 3 7 11 15
[4,] 4 8 12 16
> dat$K <- apply( dat, 1, function(x,mat) mat[ x[1], x[2] ], mat=mat )
> dat
I J K
1 1 1 1
2 2 2 6
3 3 3 11
4 4 4 16
5 1 1 1
6 2 2 6
7 3 3 11
8 4 4 16
Esto es probablemente simple de resolver. Tengo una mat
matriz 2D con 500 filas × 335 columnas y una data.frame dat
con 120425 filas. Data.frame dat
tiene dos columnas I
y J
, que son enteros para indexar la fila, columna de mat
. Me gustaría agregar los valores de mat
a las filas de dat
.
Aquí está mi error conceptual:
> dat$matval <- mat[dat$I, dat$J]
Error: cannot allocate vector of length 1617278737
(Estoy usando R 2.13.1 en Win32). Profundizando un poco más, veo que estoy haciendo un uso indebido de la indexación matricial, ya que parece que solo obtengo una submatriz de mat
, y no un conjunto de valores de una sola dimensión como esperaba, es decir:
> str(mat[dat$I[1:100], dat$J[1:100]])
int [1:100, 1:100] 20 1 1 1 20 1 1 1 1 1 ...
Esperaba algo como int [1:100] 20 1 1 1 20 1 1 1 1 1 ...
¿Cuál es la forma correcta de indexar una matriz 2D usando índices de fila, columna para obtener los valores?
Casi. Necesita ser ofrecido a "[" como una matriz de dos columnas:
dat$matval <- mat[ cbind(dat$I, dat$J) ] # should do it.
Hay una advertencia: aunque esto también funciona para dataframes, primero se les coacciona a la clase matrix y si alguno no es numérico, la matriz completa se convierte en la clase de "denominador más bajo".
Usar una matriz para indexar como sugiere DWin es, por supuesto, mucho más limpio, pero por alguna extraña razón, hacerlo manualmente usando índices 1-D es en realidad un poco más rápido:
# Huge sample data
mat <- matrix(sin(1:1e7), ncol=1000)
dat <- data.frame(I=sample.int(nrow(mat), 1e7, rep=T),
J=sample.int(ncol(mat), 1e7, rep=T))
system.time( x <- mat[cbind(dat$I, dat$J)] ) # 0.51 seconds
system.time( mat[dat$I + (dat$J-1L)*nrow(mat)] ) # 0.44 seconds
La parte dat$I + (dat$J-1L)*nrow(m)
convierte los índices 2-D en dat$I + (dat$J-1L)*nrow(m)
1-D. El 1L
es la forma de especificar un número entero en lugar de un valor doble. Esto evita algunas coerciones.
... También probé la solución basada en aplicaciones de gsk3. Aunque es casi 500 veces más lento:
system.time( apply( dat, 1, function(x,mat) mat[ x[1], x[2] ], mat=mat ) ) # 212
n <- 10
mat <- cor(matrix(rnorm(n*n),n,n))
ix <- matrix(NA,n*(n-1)/2,2)
k<-0
for (i in 1:(n-1)){
for (j in (i+1):n){
k <- k+1
ix[k,1]<-i
ix[k,2]<-j
}
}
o <- rep(NA,nrow(ix))
o <- mat[ix]
out <- cbind(ix,o)