library(learnr)
knitr::opts_chunk$set(echo = FALSE)

Introducción

knitr::include_graphics("images/matrices.jpg")

El presente tutorial pretende ser un vehículo de aprendizaje interactivo para los novatos en el lenguaje R.

Ha sido desarrollado a través del paquete learnr que permite utilizar documentos RMarkdown para generar tutoriales interactivos.

Como se explica en la página de learnr, los tutoriales consisten en contenido (texto, figuras, ilustraciones, ecuaciones, vídeos, etc.) junto con componentes interactivos, como preguntas con múltiples opciones y fragmentos de código de R que los usuarios pueden editar y ejecutar directamente, para verificar y reforzar la comprensión.

Estos tutoriales conservan automáticamente el avance que un usuario realizó, por lo que si un estudiante trabaja en algunos ejercicios o preguntas y vuelve al tutorial más tarde, puede retomarlo exactamente donde lo dejó.

Este tutorial ha sido publicado como el paquete fundamentosr.

Objetivo de aprendizaje

El objetivo de aprendizaje del presente tutorial es el siguiente:

Naturaleza y características básicas

Una matriz es una estructura compuesta de un número de elementos finitos, homogéneos y distribuidos en una estructura bidimensional de filas y columnas.

Las matrices pueden ser descritas como vectores bidimensionales. Al igual que un vector, únicamente pueden contener datos de un sólo tipo, pero además de longitud, tienen otra dimensión. Las matrices se distinguen por tener específicamente dos dimensiones, filas y columnas. Son, por lo tanto, una estructura con forma rectangular.

knitr::include_graphics("images/sudoku.jpg")

Las matrices en R son objetos de dos dimensiones que pueden contener tipos de datos simples: datos numéricos, cadena de caracteres o datos lógicos, entre otros. Cada matriz tiene dos propiedades clave:

Arrays

Cuando hablamos de un número de dimensiones superior a dos, vectores multidimensionales, la estructura de datos se conoce como array. Al igual que un vector o una matriz, únicamente pueden contener datos de un sólo tipo. En un sentido estricto, las matrices son una caso especial de un array, que se distingue por tener específicamente dos dimensiones. Puesto que las matrices son usadas de manera regular en matemáticas y estadística, las matrices son una estructura de datos de uso común en R y en la que nos enfocaremos en este tutorial.

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 de $n$ dimensiones 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.

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 segun corresponda.

Creación e inicialización

La creación e inicialización de una matriz se puede llevar a cabo mediante la función que sirve de constructor matrix() y también a través de diferentes funciones predefinidas de R que permiten unir objetos unidimensionales para obtener un objeto bidimensional.

Constructor matrix()

La sintaxis general de la orden para crear una matriz es la siguiente:

matrix(datos, nrow=nfilas, ncol=ncolumnas, byrow=FALSE)

donde:

Veamos a continuación diferentes ejemplos de creación e inicialización de una matriz a través de ejemplos:

# Creación de matriz especificando sólo el vector de datos
v <- 1:10
m <- matrix(v)
m
cat("El tipo de datos del objeto creado es",class(m))
cat("¿El objeto creado es una matriz?",is.matrix(m))
cat("El tipo de datos que contiene el objeto es",typeof(m))
dimensiones_matriz<-dim(m)
filas_matriz<-dimensiones_matriz[1]
columnas_matriz<-dimensiones_matriz[2]
cat("Las dimensiones del objeto son",dimensiones_matriz,".",filas_matriz,"filas x",columnas_matriz,"columnas.")
cat("El tipo de datos del vector utilizado para crear la matriz es",class(v))
cat("La función de dimensiones aplicada a un vector devuelve:",dim(v))

La función class()aplicada a un tipo de datos atómico como un vector devuelve el tipo de datos correspondiente a los elementos que lo integran. Esta misma función aplicada a un tipo de datos matriz devuelve el tipo de datos compuesto: matriz array. El tipo de datos correspondiente a los elementos que integran la matriz viene devuelto por typeof() o mode(). Las dimensiones del objeto matriz creado (dim()) vienen proporcionadas en un vector cuyo primer elemento son las filas (nrow()) y cuyo segundo elemento son las columnas (ncol()). Por otra parte, la función de dimensiones (dim()) aplicada a un vector devuelve NULL.


# Creación de matriz especificando el vector de datos, el número de filas y el número de columnas.
v <- 1:12
nfilas<-3
ncolumnas<-4
m1 <- matrix(v,nfilas,ncolumnas)
m1
cat("El tipo de datos que contiene la matriz es",mode(m1))
cat("Las dimensiones de la matriz son",nrow(m1),"filas x",ncol(m1),"columnas.")
# Creación de matriz especificando el vector de datos, el número de filas y el número de columnas.
nfilas<-4
ncolumnas<-3
m2 <- matrix(v,nfilas,ncolumnas)
m2
cat("Las dimensiones de la matriz son",nrow(m2),"filas x",ncol(m2),"columnas.")
# Creación de matriz especificando el vector de datos, el número de filas y el número de columnas.
nfilas<-2
ncolumnas<-6
m3 <- matrix(v,nfilas,ncolumnas)
m3
cat("Las dimensiones de la matriz son",nrow(m3),"filas x",ncol(m3),"columnas.")
# Creación de matriz especificando el vector de datos, el número de filas y el número de columnas.
nfilas<-6
ncolumnas<-2
m4 <- matrix(v,nfilas,ncolumnas)
m4
cat("Las dimensiones de la matriz son",nrow(m4),"filas x",ncol(m4),"columnas.")

Tenemos cuatro formas diferentes de crear una matriz con un vector de 12 elementos, cambiando las dimensiones de la matriz (siendo mayor en unos casos el número de filas y en otros casos el número de columnas).

Los datos que intentamos agrupar en una matriz son colocados en orden, de arriba a abajo, y de izquierda a derecha, hasta formar un rectángulo.

Si multiplicamos el número de filas por el número de columnas, obtendremos el número de celdas de la matriz. En los ejemplos anteriores, el número de celdas es igual al número de elementos que queremos almacenar.


# Creación de matriz especificando el vector de datos, el número de filas y el número de columnas.
v <- 1:12
nfilas<-3
ncolumnas<-4
m1 <- matrix(v,nfilas,ncolumnas,byrow=TRUE)
m1
cat("El tipo de datos que contiene la matriz es",mode(m1))
cat("Las dimensiones de la matriz son",nrow(m1),"filas x",ncol(m1),"columnas.")
# Creación de matriz especificando el vector de datos, el número de filas y el número de columnas.
nfilas<-4
ncolumnas<-3
m2 <- matrix(v,nfilas,ncolumnas,byrow=TRUE)
m2
cat("Las dimensiones de la matriz son",nrow(m2),"filas x",ncol(m2),"columnas.")
# Creación de matriz especificando el vector de datos, el número de filas y el número de columnas.
nfilas<-2
ncolumnas<-6
m3 <- matrix(v,nfilas,ncolumnas,byrow=TRUE)
m3
cat("Las dimensiones de la matriz son",nrow(m3),"filas x",ncol(m3),"columnas.")
# Creación de matriz especificando el vector de datos, el número de filas y el número de columnas.
nfilas<-6
ncolumnas<-2
m4 <- matrix(v,nfilas,ncolumnas,byrow=TRUE)
m4
cat("Las dimensiones de la matriz son",nrow(m4),"filas x",ncol(m4),"columnas.")

Los datos que intentamos agrupar en cada matriz son colocados en orden, de izquierda a derecha, y de arriba a abajo, hasta formar un rectángulo. En estos últimos ejemplos, nuevamente el número de celdas es igual al número de elementos del vector que queremos almacenar.


# Creación de matriz especificando un vector de datos con longitud superior al número de filas por el número de columnas.
v_cadenas <- c("Enero","Febrero","Marzo","Abril","Mayo","Junio","Julio","Agosto","Septiembre","Octubre","Noviembre","Diciembre")
nfilas<-3
ncolumnas<-3
m1 <- matrix(v_cadenas,nfilas,ncolumnas)
m1
cat("El tipo de datos que contiene la matriz es",typeof(m1))
cat("Las dimensiones de la matriz son",dim(m1)[1],"filas x",dim(m1)[2],"columnas.")
nfilas<-3
ncolumnas<-2
m2 <- matrix(v_cadenas,nfilas,ncolumnas,byrow=TRUE)
m2
cat("El tipo de datos que contiene la matriz es",typeof(m2))
cat("Las dimensiones de la matriz son",dim(m2)[1],"filas x",dim(m2)[2],"columnas.")

Podemos comprobar en ambos casos como la matriz se completa sin incluir todos los meses del año (en el primer caso, 3x3=9, y en el segundo caso, 3x2=6).


# Creación de matriz especificando un vector de datos con longitud inferior al número de filas por el número de columnas.
v_cadenas <- c("Enero","Febrero","Marzo","Abril","Mayo","Junio","Julio","Agosto","Septiembre","Octubre","Noviembre","Diciembre")
nfilas<-5
ncolumnas<-3
m1 <- matrix(v_cadenas,nfilas,ncolumnas)
m1
cat("El tipo de datos que contiene la matriz es",typeof(m1))
cat("Las dimensiones de la matriz son",dim(m1)[1],"filas x",dim(m1)[2],"columnas.")
v_logico<-c(TRUE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE)
nfilas<-2
ncolumnas<-6
m2 <- matrix(v_logico,nfilas,ncolumnas,byrow=TRUE)
m2
cat("El tipo de datos que contiene la matriz es",typeof(m2))
cat("Las dimensiones de la matriz son",dim(m2)[1],"filas x",dim(m2)[2],"columnas.")

Hemos creado dos matrices diferentes (una de cadenas de caracteres y otra de valores lógicos) cuyo número de celdas es superior a los vectores de datos. Se ha recibido la advertencia correspondiente generándose la matriz mediante el reciclado en orden de los valores del vector de datos en cada caso.


# Creación de matriz especificando sólo número de filas y número de columnas.
nfilas<-5
ncolumnas<-3
m1 <- matrix(nrow=nfilas,ncol=ncolumnas)
m1
cat("El tipo de datos que contiene la matriz es",typeof(m1))
cat("Las dimensiones de la matriz son",dim(m1)[1],"filas x",dim(m1)[2],"columnas.")

Comprobamos que la matriz se crea con un tipo de datos por defecto (logical). Todos los valores de las celdas son el valor especial NA (ausencia de valor). En este caso, es necesario especificar filas y columnas con los correspondientes parámetros nrow y ncol.


# Creación de matriz especificando vector de datos junto a únicamente número de filas o número de columnas (submúltiplo de la longitud del vector).
v<-1:15
nfilas<-5
m1 <- matrix(v,nrow=nfilas)
m1
cat("El tipo de datos que contiene la matriz es",typeof(m1))
cat("Las dimensiones de la matriz son",dim(m1)[1],"filas x",dim(m1)[2],"columnas.")

v<-1:18
ncolumnas<-3
m2 <- matrix(v,ncol=ncolumnas,byrow=TRUE)
m2
cat("El tipo de datos que contiene la matriz es",typeof(m2))
cat("Las dimensiones de la matriz son",dim(m2)[1],"filas x",dim(m2)[2],"columnas.")

En el primer caso, se especifica el número de filas únicamente y en el segundo el número de columnas únicamente.


# Creación de matriz especificando vector de datos junto a únicamente número de filas o número de columnas (múltiplo de la longitud del vector).
v<-1:4
nfilas<-12
m1 <- matrix(v,nrow=nfilas)
m1
cat("El tipo de datos que contiene la matriz es",typeof(m1))
cat("Las dimensiones de la matriz son",dim(m1)[1],"filas x",dim(m1)[2],"columnas.")

v<-1:5
ncolumnas<-15
m2 <- matrix(v,ncol=ncolumnas,byrow=TRUE)
m2
cat("El tipo de datos que contiene la matriz es",typeof(m2))
cat("Las dimensiones de la matriz son",dim(m2)[1],"filas x",dim(m2)[2],"columnas.")

# Creación de matriz especificando vector de datos junto a únicamente número de filas o número de columnas (inferior y no submúltiplo de la longitud del vector).
v<-1:4
nfilas<-3
m1 <- matrix(v,nrow=nfilas)
m1
cat("El tipo de datos que contiene la matriz es",typeof(m1))
cat("Las dimensiones de la matriz son",dim(m1)[1],"filas x",dim(m1)[2],"columnas.")

v<-1:10
ncolumnas<-3
m2 <- matrix(v,ncol=ncolumnas,byrow=TRUE)
m2
cat("El tipo de datos que contiene la matriz es",typeof(m2))
cat("Las dimensiones de la matriz son",dim(m2)[1],"filas x",dim(m2)[2],"columnas.")

En el primer caso, se especifica el número de filas, y el número de columnas más pequeño para que se supere la longitud del vector sería 2. En el segundo caso, se especifica el número de columnas, y el número de filas más pequeño para que se supere la longitud del vector sería 4. El vector de datos se repite desde el principio para completar las celdas restantes.


# Creación de matriz especificando vector de datos junto a únicamente número de filas o número de columnas (superior y no múltiplo de la longitud del vector).
v<-1:10
nfilas<-15
m1 <- matrix(v,nrow=nfilas)
m1
cat("El tipo de datos que contiene la matriz es",typeof(m1))
cat("Las dimensiones de la matriz son",dim(m1)[1],"filas x",dim(m1)[2],"columnas.")

v<-1:3
ncolumnas<-22
m2 <- matrix(v,ncol=ncolumnas,byrow=TRUE)
m2
cat("El tipo de datos que contiene la matriz es",typeof(m2))
cat("Las dimensiones de la matriz son",dim(m2)[1],"filas x",dim(m2)[2],"columnas.")

El vector de datos se reutiliza para ir rellenando en orden las celdas de la matriz creada.

Unión de vectores

Otro procedimiento para crear matrices es la unión de vectores que se puede llevar a cabo mediante las siguientes funciones:

Vamos a presentar varios ejemplos que demuestran el uso de ambas funciones para la creación de matrices.


# Creación de matriz mediante la unión de vectores de la misma longitud (columnas).
v1 <- 1:6
v2 <- c(10,20,30,40,50,60)
v3 <- rep(100,6)
v4 <- sample(c(1,2),6,replace=TRUE)
v5 <- as.integer(runif(6,min=1,max=50))

m1 <- cbind(v1,v2,v3,v4,v5)
m1
cat("El tipo de datos que contiene la matriz es",typeof(m1))
cat("Las dimensiones de la matriz son",dim(m1)[1],"filas x",dim(m1)[2],"columnas.")

vc1 <- c("A","B","C")
vc2 <- rev(vc1)
vc3 <- paste("Cadena",1:length(vc1),":",vc1,sep="_")

m2 <- cbind(vc1,vc2,vc3)
m2
cat("El tipo de datos que contiene la matriz es",typeof(m2))
cat("Las dimensiones de la matriz son",dim(m2)[1],"filas x",dim(m2)[2],"columnas.")

En el primer caso, se unen cinco vectores numéricos de una misma longitud, actuando cada uno de ellos como una columna de la matriz resultante. En el segundo caso, se unen tres vectores de cadenas de caracteres de una misma longitud, siendo cada uno de ellos una columna de la matriz generada.


# Creación de matriz mediante la unión de vectores de la misma longitud (filas).
v1 <- 1:6
v2 <- c(10,20,30,40,50,60)
v3 <- rep(100,6)
v4 <- sample(c(1,2),6,replace=TRUE)
v5 <- as.integer(runif(6,min=1,max=50))

m1 <- rbind(v1,v2,v3,v4,v5)
m1
cat("El tipo de datos que contiene la matriz es",typeof(m1))
cat("Las dimensiones de la matriz son",dim(m1)[1],"filas x",dim(m1)[2],"columnas.")

vc1 <- c("A","B","C")
vc2 <- rev(vc1)
vc3 <- paste("Cadena",1:length(vc1),":",vc1,sep="_")

m2 <- rbind(vc1,vc2,vc3)
m2
cat("El tipo de datos que contiene la matriz es",typeof(m2))
cat("Las dimensiones de la matriz son",dim(m2)[1],"filas x",dim(m2)[2],"columnas.")

En estos ejemplos, los mismos vectores usados para mostrar el funcionamiento de cbind() son utilizados con rbind(). Se puede comprobar visualmente el impacto de ambas funciones en la creación de matrices.


# Creación de matriz mediante la unión de vectores de diferente longitud (filas).
v1 <- 1:5
v2 <- 1:7
v3 <- 1:3
v4 <- 1:2
v5 <- 1:5

m1 <- rbind(v1,v2,v3,v4,v5)
m1
cat("El tipo de datos que contiene la matriz es",typeof(m1))
cat("Las dimensiones de la matriz son",dim(m1)[1],"filas x",dim(m1)[2],"columnas.")

# Creación de matriz mediante la unión de vectores de diferente longitud (columnas).


m2 <- cbind(v1,v2,v3,v4,v5)
m2
cat("El tipo de datos que contiene la matriz es",typeof(m2))
cat("Las dimensiones de la matriz son",dim(m2)[1],"filas x",dim(m2)[2],"columnas.")

En ambos casos se muestra la advertencia correspondiente.

Acceso a las celdas

Podemos saber cuántos elementos contiene una matriz mediante la función length(). El resultado de esta función es el número de celdas proporcionado por el producto de nrow() (número de filas) y ncol() (número de columnas).

Esta información nos será útil a la hora de acceder a cualquiera de los elementos de una matriz m, usando para ello la notación m[indice_filas,indice_columnas], siendo indice_filas la fila de la matriz e indice_columnas la columna de la matriz, en las que se encuentra la celda a la que queremos acceder.

v<-seq(10,120,by=10)
cat("Creamos vector de longitud",length(v))
v
m<-matrix(v,ncol=3)
cat("Matriz original:")
m
cat("Creamos matriz de",length(m),"celdas")
nfila<-1
ncolumna<-2
cat("El elemento de la fila",nfila,"y columna",ncolumna,"es",m[nfila,ncolumna])
nfila<-4
ncolumna<-3
cat("El elemento de la fila",nfila,"y columna",ncolumna,"es",m[nfila,ncolumna])

Podemos acceder también a una submatriz de una matriz dada, proporcionando un rango de índices en vez de un índice tanto para las filas como para las columnas. Veamos a continuación algunos ejemplos:

v<-seq(10,120,by=10)
cat("Creamos vector de longitud",length(v))
v
m<-matrix(v,ncol=3)
cat("Matriz original:")
m
cat("Creamos matriz de",length(m),"celdas")
nfilas<-2
ncolumnas<-2
cat("La submatriz correspondiente a las primeras",nfilas,"filas y a las primeras",ncolumnas,"columnas es")
m[1:nfilas,1:ncolumnas]
cat("La submatriz es un objeto",class(m[1:nfilas,1:ncolumnas]))

inifila<-2
finfila<-4
inicolumna<-2
fincolumna<-3
cat("La submatriz correspondiente a las filas de la",inifila,"a la",finfila,"y a las columnas de la",inicolumna,"a la",fincolumna,"es:")
m[inifila:finfila,inicolumna:fincolumna]
cat("La submatriz es un objeto",class(m[inifila:finfila,inicolumna:fincolumna]))

Cada submatriz vuelve a ser una matriz.

Veamos a continuación qué ocurre si utilizo un rango de índices para filas o columnas frente a un solo índice para columnas o filas, respectivamente.

v<-seq(10,120,by=10)
cat("Creamos vector de longitud",length(v))
v
m<-matrix(v,ncol=3)
cat("Matriz original:")
m

cat("Creamos matriz de",length(m),"celdas")
nfila<-3
inicolumna<-2
fincolumna<-3
cat("La submatriz correspondiente a la fila",nfila,"y a las columnas de la",inicolumna,"a la",fincolumna,"es:")
m[nfila,inicolumna:fincolumna]
cat("La submatriz es un objeto",class(m[nfila,inicolumna:fincolumna]))

inifila<-2
finfila<-4
ncolumna<-1
cat("La submatriz correspondiente a las filas de la",inifila,"a la",finfila,"y a la columna",ncolumna,"es:")
m[inifila:finfila,ncolumna]
cat("La submatriz es un objeto",class(m[inifila:finfila,ncolumna]))

En este caso, las submatrices son vectores.

Si no se proporciona un número de fila o un rango para filas o columnas, se entiende que nos referimos a todas las filas o todas las columnas, según corresponda. Veamos algunos ejemplos.

v_cadenas <- c("Enero","Febrero","Marzo","Abril","Mayo","Junio","Julio","Agosto","Septiembre","Octubre","Noviembre","Diciembre")
nfilas<-3
ncolumnas<-4
m1 <- matrix(v_cadenas,nfilas,ncolumnas)
cat("Matriz original:")
m1

inicol<-2
fincol<-4
cat("Si accedemos de la columna",inicol,"a la",fincol,"tendremos:")
m1[,inicol:fincol]
cat("La submatriz es un objeto",class(m1[,inicol:fincol]))

inifila<-2
finfila<-3
cat("Si accedemos de la fila",inifila,"a la",finfila,"tendremos:")
m1[inifila:finfila,]
cat("La submatriz es un objeto",class(m1[inifila:finfila,]))

ncol<-3
cat("Si accedemos a la columna",ncol,"tendremos:")
m1[,ncol]
cat("La submatriz es un objeto",class(m1[,ncol]))

nfila<-2
cat("Si accedemos a la fila",nfila,"tendremos:")
m1[nfila,]
cat("La submatriz es un objeto",class(m1[nfila,]))

Nos damos cuenta de que si solo nos referimos a una fila o una columna, el objeto resultante es un vector (de cadenas de caracteres, en el ejemplo).

Si nos fijamos en cómo se presenta una matriz al mostrarla en R, vemos que la cabecera de cada columna comienza con el selector [,ncolumna], siendo ncolumna el número de la columna correspondiente. Por otra parte, si nos fijamos en cada fila de la matriz, vemos que comienza por el selector [nfila,], siendo nfila el número de la fila correspondiente.

v_cadenas <- c("Enero","Febrero","Marzo","Abril","Mayo","Junio","Julio","Agosto","Septiembre","Octubre","Noviembre","Diciembre")
nfilas<-3
ncolumnas<-4
m1 <- matrix(v_cadenas,nfilas,ncolumnas)
m1

Existe la posibilidad de hacer uso de la excepción en el acceso a las celdas de una matriz mediante el operador - unido a un índice o un rango de índices. Veamos algunos ejemplos para demostrar su uso.

v_cadenas <- c("Enero","Febrero","Marzo","Abril","Mayo","Junio","Julio","Agosto","Septiembre","Octubre","Noviembre","Diciembre")
nfilas<-3
ncolumnas<-4
m1 <- matrix(v_cadenas,nfilas,ncolumnas)
cat("Matriz original:")
m1

inicol<-2
fincol<-4
excepfila<-3
cat("Si accedemos de la columna",inicol,"a la",fincol,"con la excepción de la fila",excepfila,"tendremos:")
m1[-excepfila,inicol:fincol]
cat("La submatriz es un objeto",class(m1[-excepfila,inicol:fincol]))

inifila<-1
finfila<-2
excepinicol<-1
excepfincol<-2
cat("Si accedemos de la fila",inifila,"a la",finfila,"con la excepción de las columnas de la",excepinicol, "a la",excepfincol,"tendremos:")
m1[inifila:finfila,-(excepinicol:excepfincol)]
cat("La submatriz es un objeto",class(m1[inifila:finfila,-(excepinicol:excepfincol)]))

ncol<-3
filasexcep<-c(1,3)
cat("Si accedemos a la columna",ncol,"con la excepción de las filas",filasexcep,"tendremos:")
m1[-filasexcep,ncol]
cat("La submatriz es un objeto",class(m1[-filasexcep,ncol]))

nfila<-2
columnasexcep<-c(1,3)
cat("Si accedemos a la fila",nfila,"con la excepción de las columnas",columnasexcep,"tendremos:")
m1[nfila,-columnasexcep]
cat("La submatriz es un objeto",class(m1[nfila,-columnasexcep]
))

ncolexcep<-3
cat("Accedemos a todas las columnas excepto la columna",ncolexcep)
m1[,-ncolexcep]
cat("La submatriz es un objeto",class(m1[,-ncolexcep]))

nfilexcep<-2
cat("Accedemos a todas las filas excepto la fila",nfilexcep)
m1[-nfilexcep,]
cat("La submatriz es un objeto",class(m1[-nfilexcep,]))

nfilexcep<-2
ncolexcep<-3
cat("Accedemos a todas las filas y columnas excepto la fila",nfilexcep,"y la columna",ncolexcep)
m1[-nfilexcep,-ncolexcep]
cat("La submatriz es un objeto",class(m1[-nfilexcep,-ncolexcep]))

La excepción se puede llevar a cabo usando filas y columnas no consecutivas, agrupando los índices en un vector.

Matrices como vectores

Toda matriz puede ser tratada como un vector con una longitud igual a su número de celdas, pudiendo accederse a la misma de ese modo.

v_cadenas <- c("Enero","Febrero","Marzo","Abril","Mayo","Junio","Julio","Agosto","Septiembre","Octubre","Noviembre","Diciembre")
nfilas<-3
ncolumnas<-4
m1 <- matrix(v_cadenas,nfilas,ncolumnas)
cat("Matriz original:")
m1

indice_vector<-9
cat("La celda",indice_vector,"de la matriz contiene el valor:",m1[indice_vector])

indice_ini<-3
indice_fin<-5
cat("Las celdas desde",indice_ini,"hasta",indice_fin,"de la matriz contienen los valores:",m1[indice_ini:indice_fin])

Teniendo en cuenta el comportamiento de la matriz como vector, podemos llevar a cabo la selección de elementos tal y como conocemos para los vectores y muestran los siguientes ejemplos:

v <- sample(-100:100,25)
nfilas<-5
m1 <- matrix(v,nrow=nfilas)
cat("Matriz original:")
m1

v_negativos<-m1[m1<0]
cat("Los números negativos de la matriz son:",v_negativos)

v_positivos<-m1[m1>0]
cat("Los números positivos de la matriz son:",v_positivos)

Asignación de nombres y valores

Las matrices pueden recibir un nombre tanto para sus filas como para sus columnas y, además, pueden modificar el contenido de sus celdas existiendo también la posibilidad de la coerción en este proceso.

Asignación de nombres

Veamos como se proporciona nombre tanto a las filas como a las columnas de una matriz a través de ejemplos. Se utilizan para ello las funciones rownames(), que recibe como argumento la matriz y devuelve los nombres asignados para las filas y colnames(), que recibe como argumento la matriz y devuelve los nombres asignados para las columnas. A ambas funciones se les puede asignar un vector de cadenas de caracteres para proporcionarles nombres a las filas o las columnas, respectivamente.

Veamos un ejemplo en el que juegan un papel fundamental los nombres para filas y columnas dentro de una matriz:

"Disponemos del número de lanzamientos de tres estudios diferentes (Warner, Disney y Fox) para los años 2011-2020. Crea una matriz en R que guarde toda esta información.

# Creación de vectores para las columnas de la matriz
warner <- c(20, 16, 17, 17, 22, 17, 18, 19, 18, 5)
disney <- c(13, 11, 8, 12, 11, 12, 8, 10, 10, 3)
fox <- c(15, 15, 15, 16, 17, 15, 13, 11, 11, 1)

# Crearemos la matriz a partir de la unión de los vectores por filas
peliculas <-rbind(warner, disney, fox)
peliculas
# Por defecto cada fila recibe el nombre del vector correspondiente.

# Vamos a añadir el nombre de las columnas: años del 2011 al 2020 (coerción implícita)
colnames(peliculas) <- 2011:2020
peliculas
#Vamos a cambiar el nombre de las filas para que sea más detallado
rownames(peliculas) <- c("Warner Bros","Walt Disney","20th Century Fox")
peliculas
#Acceso a un elemento de la matriz por nombres
nombre_estudio<-"Walt Disney"
anno<-"2015"
cat("En el año",anno,"hubo",peliculas["Walt Disney","2015"],"lanzamientos de",nombre_estudio)

#Acceso a varios elementos de la matriz por nombres
nombre_estudio<-"20th Century Fox"
annos<-c("2012","2015","2018")
cat("Número de lanzamientos de",nombre_estudio,"durante los años",annos)
peliculas[nombre_estudio,annos]

nombre_estudios<-c("Walt Disney","20th Century Fox")
annos<-c("2012","2015")
cat("Número de lanzamientos de",nombre_estudios,"durante los años",annos)
peliculas[nombre_estudios,annos]

Asignación de valores

Para la asignación de valores a las diferentes celdas de una matriz se utilizan los operadores de acceso a los elementos de la misma que ya conocemos. Se debe tener en cuenta que todos los elementos de una matriz deben ser de un mismo tipo de datos y que la coerción entrará en escena en caso necesario para garantizarlo.

Veamos varios ejemplos de asignación de valores a una matriz:

"Disponemos del número de lanzamientos de tres estudios diferentes (Warner, Disney y Fox) para los años 2011-2020. Crea una matriz en R que guarde toda esta información.

2011 | 2012 | 2013 | 2014 | 2015 | 2016 | 2017 | 2018 | 2019 | 2020 | 2021 :--:|:--:|:--:|:--:|:--:|:--:|:--:|:--:|:--:|:--:|:--:| 13 | 13| 8 | 10| 9 | 12| 10| 10| 9 | 3 | 8 | "

# Creación de vectores para las columnas de la matriz
Warner <- c(20, 16, 17, 17, 22, 17, 18, 19, 18, 5)
Disney <- c(13, 11, 8, 12, 11, 12, 8, 10, 10, 3)
Fox <- c(15, 15, 15, 16, 17, 15, 13, 11, 11, 1)

# Crearemos la matriz a partir de la unión de los vectores por filas
peliculas <-rbind(Warner, Disney, Fox)
# Vamos a añadir el nombre de las columnas: años del 2011 al 2020 (coerción implícita)
colnames(peliculas) <- 2011:2020
cat("Lanzamientos 2011-2020")
peliculas

#Creamos un vector que contiene los lanzamientos de 2021 en el mismo orden que aparece en la matriz
lanzamientos_2021<-c(17,10,0)
#Unimos el vector como nueva columna de la matriz
peliculas<-cbind(peliculas,lanzamientos_2021)
#Le asignamos un nombre a la nueva columna (colocada al final)
colnames(peliculas)[length(colnames(peliculas))]<-"2021"
cat("Lanzamientos 2011-2021")
peliculas

#Modificamos los lanzamientos de disney para 2020 añadiendo uno más
cat("Lanzamientos 2011-2021 añadiendo uno más a Disney, 2020")
nombre_estudio<-"Disney"
anno<-"2020"
peliculas[nombre_estudio,anno]<-peliculas[nombre_estudio,anno]+1
peliculas

#Modificamos los lanzamientos para 2011 reduciendo dos
cat("Lanzamientos 2011-2021 reduciendo dos para 2011")
anno<-"2011"
peliculas[,anno]<-peliculas[,anno]-2
peliculas

#Creamos un vector que contiene los lanzamientos del nuevo estudio en el mismo orden que aparece en la matriz
Paramount<-c(13,13,8,10,9,12,10,10,9,3,8)
#Unimos el vector como nueva fila de la matriz
peliculas<-rbind(peliculas,Paramount)
cat("Lanzamientos 2011-2021 con el nuevo estudio")
peliculas

Asignación y coerción

Finalmente, veremos diferentes ejemplos de asignación de valores a una matriz en los que se muestra el papel de la coerción tanto explícita como implícita.

#Creamos vector de cadenas de caracteres
meses<-c("Enero","Febrero","Marzo","Abril","Mayo","Junio","Julio","Agosto","Septiembre","Octubre","Noviembre","Diciembre")
#Creamos vector de enteros
dias<-c(31,28,31,30,31,30,31,31,30,31,30,31)
#Unimos para crear matriz
anno<-rbind(meses,dias)
anno

#Creamos vector numérico (flotantes)
temperatura<-c(8.4,9.8,12.7,15.6,20.1,25.7,28.7,28.6,24.1,19,12.4,9.4)
#Añadimos a matriz de cadenas de caracteres
anno<-rbind(anno,temperatura)
anno

#Creamos vector lógico
lluvia<-c(TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE,TRUE,TRUE,TRUE)
#Añadimos a matriz de cadenas de caracteres
anno<-rbind(anno,lluvia)
anno

En este primer ejemplo, se produce la coerción implícita de todos los valores de los vectores (numéricos y lógicos) a cadenas de caracteres cuando se unen para obtener la matriz, en cada caso.

#Creamos vector numérico (enteros)
meses<-c(1,2,3,4,5,6,7,8,9,10,11,12)
#Creamos vector numérico (enteros)
dias<-c(31,28,31,30,31,30,31,31,30,31,30,31)
#Unimos para crear matriz
anno<-rbind(meses,dias)
anno
typeof(anno)
#Creamos vector numérico (flotantes)
temperatura<-c(8.4,9.8,12.7,15.6,20.1,25.7,28.7,28.6,24.1,19,12.4,9.4)
#Añadimos a matriz
anno<-rbind(anno,temperatura)
anno
typeof(anno)

#Creamos vector lógico
lluvia<-c(TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE,TRUE,TRUE,TRUE)
#Añadimos a matriz
anno<-rbind(anno,lluvia)
anno
typeof(anno)

En este ejemplo, se produce la coerción implícita de todos los valores de los vectores (numéricos y lógicos) a double cuando se unen para constituir la matriz.

#Creamos vector numérico (enteros)
meses<-as.integer(c(1,2,3,4,5,6,7,8,9,10,11,12))
#Creamos vector numérico (enteros)
dias<-as.integer(c(31,28,31,30,31,30,31,31,30,31,30,31))
#Unimos para crear matriz
anno<-rbind(meses,dias)
anno
typeof(anno)
#Creamos vector numérico (flotantes)
temperatura<-as.integer(c(8.4,9.8,12.7,15.6,20.1,25.7,28.7,28.6,24.1,19,12.4,9.4))
#Añadimos a matriz
anno<-rbind(anno,temperatura)
anno
typeof(anno)

#Creamos vector lógico
lluvia<-c(TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE,TRUE,TRUE,TRUE)
#Añadimos a matriz
anno<-rbind(anno,lluvia)
anno
typeof(anno)

En este último ejemplo se hace uso de la coerción explícita, por una parte, para que todos los vectores numéricos sean coercionados en su aportación a la matriz a integer. Por otra parte, el vector lógico es coercionado a integer mediante coerción implícita cuando se une a la matriz.

Operaciones y funciones predefinidas

Podemos aplicar diferentes operaciones y funciones predefinidas de R específicas para el tipo de datos matriz. Dada la naturaleza de este tipo de datos bidimensional hemos de analizar tanto el efecto de las operaciones, ya conocido sobre otros tipos de datos, como las nuevas funciones predefinidas específicas de este tipo de datos.

Operaciones aritméticas

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.

Operación | Operando | Sintaxis | :--|:--|:--: Adición | Escalar o matriz | + Sustracción | Escalar o matriz | - Multiplicación | Escalar o matriz | * - | Matrices | %*% División | Escalar o matriz | / Potencia | Escalar | ^

Veamos a continuación ejemplos para cada una de las operaciones aritméticas:

# Creamos una matriz de ejemplo
v<-1:20
ncolumnas<-4
m<-matrix(v,ncol=ncolumnas)
cat("Matriz original:")
m
#Sumamos con un escalar
escalar<-4
m_res<-m+4
cat("Añadimos escalar: +",escalar)
m_res
#Creamos matriz adicional con las mismas dimensiones
m2<-matrix(11:30,ncol=ncolumnas)
cat("Nueva matriz:")
m2
cat("Sumamos matriz original con nueva matriz:")
m_res2<-m+m2
m_res2

Podemos comprobar como la suma con escalar se aplica celda a celda de la matriz. La suma entre matrices se realiza entre los elementos ubicados en la misma posición (fila y columna) y aparece en la matriz resultado en esa misma ubicación.

# Creamos una matriz de ejemplo
v<-1:20
ncolumnas<-4
m<-matrix(v,ncol=ncolumnas)
cat("Matriz original:")
m
#Restamos con un escalar
escalar<-4
m_res<-m-4
cat("Restamos escalar: -",escalar)
m_res
#Creamos matriz adicional con las mismas dimensiones
m2<-matrix(11:30,ncol=ncolumnas)
cat("Nueva matriz:")
m2
cat("Restamos matriz original con nueva matriz:")
m_res2<-m-m2
m_res2

Nuevamente la resta con escalar se aplica celda a celda de la matriz. La resta entre matrices, al igual que la suma, se realiza entre los elementos ubicados en la misma posición (fila y columna) y aparece en la matriz resultado en esa misma ubicación.

# Creamos una matriz de ejemplo
v<-1:20
ncolumnas<-4
m<-matrix(v,ncol=ncolumnas)
cat("Matriz original:")
m
#Multiplicamos por un escalar
escalar<-4
m_res<-m*4
cat("Multiplicamos por escalar: *",escalar)
m_res
#Creamos matriz adicional con las mismas dimensiones
m2<-matrix(11:30,ncol=ncolumnas)
cat("Nueva matriz:")
m2
cat("Multiplicamos matriz original por nueva matriz (elemento a elemento):")
m_res2<-m*m2
m_res2

Para la multiplicación elemento a elemento ocurre lo mismo que para la suma y la resta tanto con un escalar como con una matriz. Sin embargo, la multiplicación de matrices como tal se lleva a cabo mediante el símbolo %*%. Veamos el siguiente ejemplo.

# Creamos una matriz de ejemplo
v<-1:20
ncolumnas<-4
nfilas<-5
m<-matrix(v,ncol=ncolumnas)
cat("Matriz original:")
m
#Creamos matriz adicional con las mismas dimensiones
m2<-matrix(11:30,ncol=nfilas)
cat("Nueva matriz:")
m2
cat("Multiplicamos matriz original por nueva matriz:")
m_res<-m%*%m2
m_res
cat("Multiplicamos nueva matriz por matriz original:")
m_res2<-m2%*%m
m_res2

Recordemos que solo se puede multiplicar dos matrices si sus dimensiones son compatibles, lo que significa que el número de columnas en la primera matriz es igual al número de filas en la segunda matriz. Así mismo, la multiplicación de matrices no es conmutativa, depende del orden de multiplicación.

# Creamos una matriz de ejemplo
v<-1:20
ncolumnas<-4
m<-matrix(v,ncol=ncolumnas)
cat("Matriz original:")
m
#Dividimos por un escalar
escalar<-4
m_res<-m/4
cat("Dividimos por escalar: /",escalar)
m_res
#Creamos matriz adicional con las mismas dimensiones
m2<-matrix(11:30,ncol=ncolumnas)
cat("Nueva matriz:")
m2
cat("Dividimos matriz original entre nueva matriz (elemento a elemento):")
m_res2<-m/m2
m_res2

El efecto de la operación de división es similar al de la suma, resta y multiplicación elemento a elemento. Finalmente comprobaremos el efecto de la potencia con un escalar.

# Creamos una matriz de ejemplo
v<-1:20
ncolumnas<-4
m<-matrix(v,ncol=ncolumnas)
cat("Matriz original:")
m
#Potencia con un escalar
escalar<-2
m_res<-m^2
cat("Potencia: ^",escalar)
m_res

En el caso de la potencia, si el exponente es por ejemplo 2 tendría el efecto de multiplicar la matriz por sí misma (elemento a elemento).

Funciones predefinidas

Existen numerosas funciones predefinidas en R orientadas a la operación con matrices teniendo en cuenta las características y posibilidades de esta estructura de datos bidimensional. Comenzaremos con algunas de las funciones predefinidas utilizadas en álgebra lineal.

Álgebra lineal

A continuación presentaremos algunas de las funciones predefinidas que dispone R para álgebra lineal con matrices.

Operación | Función | :--|:--: Transpuesta | t() Diagonal | diag() Traza | sum(diag()) Determinante | det() Inversa | solve()

Veamos algunos ejemplos que demuestran el uso de estas funciones:

# Creamos una matriz de ejemplo
v<-1:20
ncolumnas<-4
m<-matrix(v,ncol=ncolumnas)
cat("Matriz original:")
m
# Creamos una matriz cuadrada de ejemplo
v<-sample(-16:16,16,replace=TRUE)
ncolumnas<-4
mc<-matrix(v,ncol=ncolumnas)
cat("Matriz original cuadrada:")
mc

# Calculamos su transpuesta
mt<-t(m)
cat("Matriz transpuesta:")
mt
mct<-t(mc)
cat("Matriz cuadrada transpuesta:")
mct


cat("Diagonal de matriz original")
md<-diag(m)
md
cat("Diagonal de matriz original cuadrada:")
mcd<-diag(mc)
mcd

trazam<-sum(diag(m))
cat("Traza de la matriz original",trazam)
trazamc<-sum(diag(mc))
cat("Traza de la matriz original cuadrada",trazamc)

#detm<-det(m)
#cat("Determinante de la matriz original",detm)
detmc<-det(mc)
cat("Determinante de la matriz original",detmc)

#invm<-solve(m)
#invm
cat("Inversa de la matriz original cuadrada")
invmc<-solve(mc)
invmc
cat("Resultado de multiplicar la matriz original cuadrada por su inversa")
identidad<-mc%*%invmc
identidad
cat("Por cuestiones de precisión todo número muy cercano a 0 lo consideramos 0 y todo número muy cercano a 1 lo consideramos 1")
cat("El resultado de la multiplicación de la matriz original cuadrada por su inversa es la identidad.")
identidad[(identidad<0.000001)&(identidad>-0.000001)]<-0
identidad[(identidad>0.999999)&(identidad<1.000001)]<-1
identidad

Funciones por filas o por columnas

colMeans() rowMeans() colSums() rowSums()



eyeguas/fundamentosr documentation built on March 31, 2021, 5:20 p.m.