6.2 Matrices y arrays

Las matrices y arrays pueden ser descritas como vectores multidimensionales. Al igual que un vector, únicamente pueden contener datos de un sólo tipo, pero además de largo, tienen más dimensiones.

En un sentido estricto, las matrices son una caso especial de un array, que se distingue por tener específicamente dos dimensiones, un “largo”" y un “alto”. Las matrices son, por lo tanto, una estructura con forma rectangular, con renglones y columnas.

Como las matrices son usadas de manera regular en matemáticas y estadística, es una estructura de datos de uso común en R común y en la que nos enfocaremos en este libro.

Los arrays, por su parte, pueden tener un número arbitrario de dimensiones. Pueden ser cubos, hipercubos y otras formas. Su uso no es muy común en R, aunque a veces es deseable contar con objetos n-dimensionales para manipular datos. Como los arrays tienen la restricción de que todos sus datos deben ser del mismo tipo, no importando en cuántas dimensiones se encuentren, esto limita sus usos prácticos.

En general, es preferible usar listas en lugar de arrays, una estructura de datos que además tienen ciertas ventajas que veremos más adelante.

6.2.1 Creación de matrices

Creamos matrices en R con la función matrix(). La función matrix() acepta dos argumentos, nrow y ncol. Con ellos especificamos el número de renglones y columnas que tendrá nuestra matriz.

# Un vector numérico del uno al doce
1:12
##  [1]  1  2  3  4  5  6  7  8  9 10 11 12
# matrix() sin especificar renglones ni columnas
matrix(1:12)
##       [,1]
##  [1,]    1
##  [2,]    2
##  [3,]    3
##  [4,]    4
##  [5,]    5
##  [6,]    6
##  [7,]    7
##  [8,]    8
##  [9,]    9
## [10,]   10
## [11,]   11
## [12,]   12
# Tres renglones y cuatro columnas
matrix(1:12, nrow = 3, ncol = 4)
##      [,1] [,2] [,3] [,4]
## [1,]    1    4    7   10
## [2,]    2    5    8   11
## [3,]    3    6    9   12
# Cuatro columnas y tres columnas
matrix(1:12, nrow = 4, ncol = 3)
##      [,1] [,2] [,3]
## [1,]    1    5    9
## [2,]    2    6   10
## [3,]    3    7   11
## [4,]    4    8   12
# Dos renglones y seis columnas
matrix(1:12, nrow = 4, ncol = 3)
##      [,1] [,2] [,3]
## [1,]    1    5    9
## [2,]    2    6   10
## [3,]    3    7   11
## [4,]    4    8   12

Los datos que intentemos agrupar en una matriz serán acomodados en orden, de arriba a abajo, y de izquierda a derecha, hasta formar un rectángulo.

Si multiplicamos el número de renglones por el número de columnas, obtendremos el número de celdas de la matriz. En los ejemplo anteriores, el número de celdas es igual al número de elementos que queremos acomodar, así que la operación ocurre sin problemas.

Cuando intentamos acomodar un número diferente de elementos y celdas, ocurren dos cosas diferentes.

Si el número de elementos es mayor al número de celdas, se acomodarán todos los datos que sean posibles y los demás se omitirán.

matrix(1:12, nrow = 3, ncol = 3)
##      [,1] [,2] [,3]
## [1,]    1    4    7
## [2,]    2    5    8
## [3,]    3    6    9

Si, por el contrario, el número de celdas es mayor que el número de elementos, estos se reciclaran. En cuanto los elementos sean insuficientes para acomodarse en las celdas, R nos devolverá una advertencia y se empezaran a usar los elementos a partir del primero de ellos

matrix(1:12, nrow = 5, ncol = 4)
## Warning in matrix(1:12, nrow = 5, ncol = 4): data length [12] is not a sub-
## multiple or multiple of the number of rows [5]
##      [,1] [,2] [,3] [,4]
## [1,]    1    6   11    4
## [2,]    2    7   12    5
## [3,]    3    8    1    6
## [4,]    4    9    2    7
## [5,]    5   10    3    8

Otro procedimiento para crear matrices es la unión vectores con las siguientes funciones:

  • cbind() para unir vectores, usando cada uno como una columna.
  • rbind() para unir vectores, usando cada uno como un renglón.

De este modo podemos crear cuatro vectores y unirlos para formar una matriz. Cada vector será un renglón en esta matriz.

Creamos cuatro vectores, cada uno de largo igual a cuatro.

vector_1 <- 1:4
vector_2 <- 5:8
vector_3 <- 9:12
vector_4 <- 13:16

Usamos rbind() para crear un matriz, en la que cada vector será un renglón.

matriz <- rbind(vector_1, vector_2, vector_3, vector_4)

# Resultado
matriz
##          [,1] [,2] [,3] [,4]
## vector_1    1    2    3    4
## vector_2    5    6    7    8
## vector_3    9   10   11   12
## vector_4   13   14   15   16

Si utilizamos cbind(), entonces cada vector será una columna.

matriz <- cbind(vector_1, vector_2, vector_3, vector_4)

# Resultado
matriz
##      vector_1 vector_2 vector_3 vector_4
## [1,]        1        5        9       13
## [2,]        2        6       10       14
## [3,]        3        7       11       15
## [4,]        4        8       12       16

Al igual que con matrix(), los elementos de los vectores son reciclados para formar una estructura rectangular y se nos muestra un mensaje de advertencia.

# Elementos de largo diferente
vector_1 <- 1:2
vector_2 <- 1:3
vector_3 <- 1:5

matriz <- cbind(vector_1, vector_2, vector_3)
## Warning in cbind(vector_1, vector_2, vector_3): number of rows of result is
## not a multiple of vector length (arg 1)
# Resultado
matriz
##      vector_1 vector_2 vector_3
## [1,]        1        1        1
## [2,]        2        2        2
## [3,]        1        3        3
## [4,]        2        1        4
## [5,]        1        2        5

Finalmente, las matrices pueden contener NAs.

Creamos dos vectores con un NA en ellos.

vector_1 <- c(NA, 1, 2)
vector_2 <- c(3,  4, NA)

Creamos una matriz con rbind().

matriz <- rbind(vector_1, vector_2)

# Resultados
matriz
##          [,1] [,2] [,3]
## vector_1   NA    1    2
## vector_2    3    4   NA

Como NA representa datos perdidos, puede estar presente en compañía de todo tipo de de datos.

6.2.2 Propiedades de las matrices

No obstante que las matrices y arrays son estructuras que sólo pueden contener un tipo de datos, no son atómicas. Su clase es igual a matriz (matrix) o array según corresponda.

Verificamos esto usando la función class().

mi_matriz <- matrix(1:10)

class(mi_matriz)
## [1] "matrix"

Las matrices y arrays pueden tener más de una dimensión.

Obtenemos el número de dimensiones de una matriz o array con la función dim(). Esta función nos devolverá varios números, cada uno de ellos indica la cantidad de elementos que tiene una dimensión.

mi_matriz <- matrix(1:12, nrow = 4, ncol = 3)
dim(mi_matriz)
## [1] 4 3

Cabe señalar que si usamos dim() con un vector, obtenemos NULL. Esto ocurre con todos los objetos unidimensionales

mi_vector <- 1:12

dim(mi_vector)
## NULL

Finalmente, las operaciones aritméticas también son vectorizadas al aplicarlas a una matriz. La operación es aplicada a cada uno de los elementos de la matriz.

Creamos una matriz.

mi_matriz <- matrix(1:9, nrow = 3, ncol = 3)

# Resultado
mi_matriz
##      [,1] [,2] [,3]
## [1,]    1    4    7
## [2,]    2    5    8
## [3,]    3    6    9

Intentemos sumar, multiplicar y elevar a la tercera potencia.

# Suma
mi_matriz + 1
##      [,1] [,2] [,3]
## [1,]    2    5    8
## [2,]    3    6    9
## [3,]    4    7   10
# Multiplicación
mi_matriz * 2
##      [,1] [,2] [,3]
## [1,]    2    8   14
## [2,]    4   10   16
## [3,]    6   12   18
# Potenciación
mi_matriz ^ 3
##      [,1] [,2] [,3]
## [1,]    1   64  343
## [2,]    8  125  512
## [3,]   27  216  729

Si intentamos vectorizar una operación utilizando una matriz con NAs, esta se aplicará para los elementos válidos, devolviendo NA cuando corresponda.

Creamos una matriz con NAs.

vector_1 <- c(NA, 2, 3)
vector_2 <- c(4, 5, NA)

matriz <- rbind(vector_1, vector_2)

# Resultado
matriz
##          [,1] [,2] [,3]
## vector_1   NA    2    3
## vector_2    4    5   NA

Intentamos dividir sus elementos entre dos.

matriz / 2
##          [,1] [,2] [,3]
## vector_1   NA  1.0  1.5
## vector_2    2  2.5   NA

Finalmente, podemos usar la función t() para transponer una matriz, es decir, rotarla 90°.

Creamos una matriz con tres renglones y dos columnas.

matriz <- matrix(1:6, nrow = 3)

# Resultado
matriz
##      [,1] [,2]
## [1,]    1    4
## [2,]    2    5
## [3,]    3    6

Usamos t() para transponer.

matriz_t <- t(matriz)

# Resultado
matriz_t
##      [,1] [,2] [,3]
## [1,]    1    2    3
## [2,]    4    5    6

Obtenemos una matriz con dos renglones y dos columnas.