Uso de matrices, dataframes y importación de datos
Creado: 25-08-2021
En el siguiente documento veremos como usar y declarar las matrices, como crear dataframes y por ultimo veremos como importar e exportar datos desde Rstudio.
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 esta clase.
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.
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): la longitud de los datos [12] no es
## un submúltiplo o múltiplo del número de filas [5] en la matriz
## [,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:16Usamos 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
print(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)# Resultados
print(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:5matriz <- 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.
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 segun 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
library(Biodem)
mtx.exp(mi_matriz,3)## [,1] [,2] [,3]
## [1,] 468 1062 1656
## [2,] 576 1305 2034
## [3,] 684 1548 2412
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.
En el siguiente ejercicio haremos uso de las matrices para el desarrollo del siguiente problema de regresión por minímos cuadrados ordinarios (MCO).
edad<-c(56,42,72,36,63,47,55,47,38,42)
presion<-c(148,126,159,118,149,130,151,142,114,141)plot(edad,presion,main="Diagrama de disperción")modelo=lm(presion~edad)summary(modelo)
Call:
lm(formula = presion ~ edad)
Residuals:
Min 1Q Median 3Q Max
-10.210 -4.277 -3.361 6.173 12.183
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 80.4445 11.0217 7.299 8.4e-05 ***
edad 1.1517 0.2162 5.328 0.000704 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 7.487 on 8 degrees of freedom
Multiple R-squared: 0.7802, Adjusted R-squared: 0.7527
F-statistic: 28.39 on 1 and 8 DF, p-value: 0.000704
| Dependent variable: | |
| presion | |
| edad | 1.152*** |
| (0.216) | |
| Constant | 80.444*** |
| (11.022) | |
| Observations | 10 |
| R2 | 0.780 |
| Adjusted R2 | 0.753 |
| Residual Std. Error | 7.487 (df = 8) |
| F Statistic | 28.390*** (df = 1; 8) |
| Note: | p<0.1; p<0.05; p<0.01 |
plot(edad,presion,main = "Gráfico de Regresión lineal")
abline(modelo,col="red",lty=2)x<- cbind(1,edad)
print(head(x))## edad
## [1,] 1 56
## [2,] 1 42
## [3,] 1 72
## [4,] 1 36
## [5,] 1 63
## [6,] 1 47
y<- cbind(presion)
print(head(y))## presion
## [1,] 148
## [2,] 126
## [3,] 159
## [4,] 118
## [5,] 149
## [6,] 130
tx<- t(x)
print(head(tx))## [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
## 1 1 1 1 1 1 1 1 1 1
## edad 56 42 72 36 63 47 55 47 38 42
x_x<- tx%*%x
print(head(x_x))## edad
## 10 498
## edad 498 26000
library(MASS)det(x_x)## [1] 11996
invx_x<- ginv(x_x)xy<-tx%*%y
print(xy)## presion
## 1378
## edad 70006
beta<- invx_x%*%xyprint(beta)## presion
## [1,] 80.444481
## [2,] 1.151717
Los data frames son estructuras de datos de dos dimensiones (rectangulares) que pueden contener datos de diferentes tipos, por lo tanto, son heterogéneas. Esta estructura de datos es la más usada para realizar análisis de datos y seguro te resultará familiar si has trabajado con otros paquetes estadísticos.
Podemos entender a los data frames como una versión más flexible de una matriz. Mientras que en una matriz todas las celdas deben contener datos del mismo tipo, los renglones de un data frame admiten datos de distintos tipos, pero sus columnas conservan la restricción de contener datos de un sólo tipo.
En términos generales, los renglones en un data frame representan casos, individuos u observaciones, mientras que las columnas representan atributos, rasgos o variables. Por ejemplo, así lucen los primeros cinco renglones del objeto iris, el famoso conjunto de datos Iris de Ronald Fisher, que está incluido en todas las instalaciones de R.
print(head(iris,20)) Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 5.1 3.5 1.4 0.2 setosa
2 4.9 3.0 1.4 0.2 setosa
3 4.7 3.2 1.3 0.2 setosa
4 4.6 3.1 1.5 0.2 setosa
5 5.0 3.6 1.4 0.2 setosa
6 5.4 3.9 1.7 0.4 setosa
7 4.6 3.4 1.4 0.3 setosa
8 5.0 3.4 1.5 0.2 setosa
9 4.4 2.9 1.4 0.2 setosa
10 4.9 3.1 1.5 0.1 setosa
11 5.4 3.7 1.5 0.2 setosa
12 4.8 3.4 1.6 0.2 setosa
13 4.8 3.0 1.4 0.1 setosa
14 4.3 3.0 1.1 0.1 setosa
15 5.8 4.0 1.2 0.2 setosa
16 5.7 4.4 1.5 0.4 setosa
17 5.4 3.9 1.3 0.4 setosa
18 5.1 3.5 1.4 0.3 setosa
19 5.7 3.8 1.7 0.3 setosa
20 5.1 3.8 1.5 0.3 setosa
Los primeros cinco renglones corresponden a cinco casos, en este caso flores. Las columnas son variables con los rasgos de cada flor: largo y ancho de sépalo, largo y ancho de pétalo, y especie.
Para crear un data frame usamos la función data.frame(). Esta función nos pedirá un número de vectores igual al número de columnas que deseemos. Todos los vectores que proporcionemos deben tener el mismo largo.
Esto es muy importante: Un data frame está compuesto por vectores.
Más adelante se hará evidente porque esta característica de un data frame es sumamente importante y también, cómo podemos sacarle provecho.
Además, podemos asignar un nombre a cada vector, que se convertirá en el nombre de la columna. Como todos los nombres, es recomendable que este sea claro, no ambiguo y descriptivo.
mi_df <- data.frame(
"entero" = 1:4,
"factor" = c("a", "b", "c", "d"),
"numero" = c(1.2, 3.4, 4.5, 5.6),
"cadena" = as.character(c("a", "b", "c", "d"))
)
mi_df## entero factor numero cadena
## 1 1 a 1.2 a
## 2 2 b 3.4 b
## 3 3 c 4.5 c
## 4 4 d 5.6 d
# Podemos usar dim() en un data frame
dim(mi_df)## [1] 4 4
# El largo de un data frame es igual a su número de columnas
length(mi_df)## [1] 4
# names() nos permite ver los nombres de las columnas
names(mi_df)## [1] "entero" "factor" "numero" "cadena"
# La clase de un data frame es data.frame
class(data.frame) ## [1] "function"
Si los vectores que usamos para construir el data frame no son del mismo largo, los datos no se reciclaran. Se nos devolverá un error.
data.frame(
"entero" = 1:3,
"factor" = c("a", "b", "c", "d"),
"numero" = c(1.2, 3.4, 4.5, 5.6),
"cadena" = as.character(c("a", "b", "c", "d"))
)## Error in data.frame(entero = 1:3, factor = c("a", "b", "c", "d"), numero = c(1.2, : arguments imply differing number of rows: 3, 4
También podemos coercionar esta matriz a un data frame.
Creamos una matriz.
matriz <- matrix(1:12, ncol = 4)Usamos as.data.frame() para coercionar una matriz a un data frame.
df <- as.data.frame(matriz)Verificamos el resultado
class(df)## [1] "data.frame"
# Resultado
df## V1 V2 V3 V4
## 1 1 4 7 10
## 2 2 5 8 11
## 3 3 6 9 12
Al igual que con una matriz, si aplicamos una operación aritmética a un data frame, esta se vectorizará.
Los resultados que obtendremos dependerán del tipo de datos de cada columna. R nos devolverá todas las advertencias que ocurran como resultado de las operaciones realizadas, por ejemplo, aquellas que hayan requerido una coerción.
mi_df <- data.frame(
"entero" = 1:4,
"factor" = c("a", "b", "c", "d"),
"numero" = c(1.2, 3.4, 4.5, 5.6),
"cadena" = as.character(c("a", "b", "c", "d"))
)
mi_df * 2## entero factor numero cadena
## 1 2 NA 2.4 NA
## 2 4 NA 6.8 NA
## 3 6 NA 9.0 NA
## 4 8 NA 11.2 NA