Tema 3. Estructuras de datos

3.1 Vectores, matrices y tablas

Diferencias entre Slicing & Subsetting

Limpiando variables de la consola de R

1. Vectores

Una de las ventajas de R es que es muy bueno para manejar vectores, matrices y “data frames”, y para hacer cálculos vectoriales y matriciales, de manera nativa. De hecho, cuando utilizamos variables escalares en R, en el fondo es como si fueran vectores con un solo elemento.

Los vectores deben ser de un solo tipo de dato. Hay muchas maneras de crear vectores. Podemos utilizar:

1. : para secuencias ascendentes o descendentes de pasos unitarios

2. seq( ) para secuencias más complejas, con pasos en múltiplos, etc. (“sequence”)

3. rep( ) para replicar patrones, con opción de intercalado, etc. (“replicate”)

4. c( ) para combinar varios datos en un solo vector (“combine”)

Prueba los siguientes ejemplos:

1:10
##  [1]  1  2  3  4  5  6  7  8  9 10
seq(from = 0, to = 10) # Por default se incrementa de 1 en 1
##  [1]  0  1  2  3  4  5  6  7  8  9 10
seq(0, 10, by = 2) # Se puede hacer que los incrementos o decrementos sean diferentes a 1
## [1]  0  2  4  6  8 10
x <- 10:1 # Secuencia descendente

x
##  [1] 10  9  8  7  6  5  4  3  2  1
rep("Oe", 10)
##  [1] "Oe" "Oe" "Oe" "Oe" "Oe" "Oe" "Oe" "Oe" "Oe" "Oe"
indu <- c("Health Care", "Financials", "Info Tech", "Materials", "Industrials")
indu
## [1] "Health Care" "Financials"  "Info Tech"   "Materials"   "Industrials"

c( ) es una de las maneras más comunes para crear vectores de manera manual, dado que no siempre ocupamos algo con un patrón numérico, pero es práctico saber que están las demás alternativas.

Nota como los ejemplos abajo dan el mismo resultado:

1:10
##  [1]  1  2  3  4  5  6  7  8  9 10
c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
##  [1]  1  2  3  4  5  6  7  8  9 10

Un concepto importante al manejar arreglos (“arrays”) como vectores y matrices es el poder referirnos a solo una parte, un subconjunto o un elemento en particular. A esto se le conoce como “subsetting” o “slicing”.

En R, el índice que indica la posición ya sea en vectores o en renglones y columnas de matrices comienza siempre en 1. Esto hace R muy amigable para no-programadores, pero si ya conoces otros lenguajes como Python, notarás que es una diferencia importante. En muchos lenguajes de programación los índices comienzan en 0. Por tanto, al “traducir” un algoritmo de R a Python o viceversa no solo es necesario ajustar la sintaxis y los nombres de las funciones sino también los índices.

Veamos los siguientes ejemplos de “subsetting” en R.

Se puede usar subsetting para acceder elementos de posiciones específicas:

indu[1]
## [1] "Health Care"
indu[2:4]
## [1] "Financials" "Info Tech"  "Materials"
indu[c(1,5)]
## [1] "Health Care" "Industrials"

También se puede usar subsetting para reemplazar elementos de posiciones específicas:

indu[5] <- "Real Estate"
indu
## [1] "Health Care" "Financials"  "Info Tech"   "Materials"   "Real Estate"
indu[4:5] <- c("Energy", "Utilities")
indu
## [1] "Health Care" "Financials"  "Info Tech"   "Energy"      "Utilities"

E incluso se puede hacer subsetting para agregar elementos a un vector ya existente.

indu[7] <- c("Consumer Staples")
indu
## [1] "Health Care"      "Financials"       "Info Tech"        "Energy"          
## [5] "Utilities"        NA                 "Consumer Staples"

Dado que agregamos un elemento a la posición 7 y solo tenía 5 posiciones el vector, nota como llenó en automático la posición 6 con un NA que significa “no disponible” (“Not Available”).

En el caso de R, podemos usar índices negativos para hacer un subsetting donde omitamos esa posición (a diferencia de Python donde índices negativos son conteo en reversa).

Ve este ejemplo donde se muestra el vector indu excluyendo su tercer elemento. Ojo que, en este ejemplo, el objeto indu sigue teniendo siete elementos (como puedes confirmar en el ambiente global).

indu[-3]
## [1] "Health Care"      "Financials"       "Energy"           "Utilities"       
## [5] NA                 "Consumer Staples"
indu[-c(1,5)]
## [1] "Financials"       "Info Tech"        "Energy"           NA                
## [5] "Consumer Staples"

Si queremos quitar elementos de manera permanente y no solo al desplegar indu, hay que reemplazarlo o sobreescribirlo de la siguiente manera:

indu <- indu[-(6:7)]
indu
## [1] "Health Care" "Financials"  "Info Tech"   "Energy"      "Utilities"

2. Matrices

Al igual que los vectores, las matrices son estructuras de un solo tipo de dato, pero en dos dimensiones en vez de una. El estándar de coordenadas en R cuando se tienen dos dimensiones es: [renglón, columna].

Típicamente las matrices tienen datos numéricos y su caso de uso común es para álgebra matricial, que se utiliza para resolver ecuaciones simultáneas, para optimización y para simulación.

Hay varias formas de generar matrices en R, además de leerlas de otra fuente. Las funciones típicas para crear matrices son matrix( ) y array( ). Dado que matrix( ) es la función más directo y con este propósito específico, nos enfocaremos en esa. Sin embargo, también puedes revisar la documentación de ?array para ver las diferencias. Te adelanto que array( ) es más general y sirve para crear objetos de 1, 2, 3 o más dimensiones, pero no usaremos más de 2D en este curso.

Estos dos ejemplos generan el mismo resultado:

x <- matrix(data = 1:12, nrow = 3, ncol = 4)
x
##      [,1] [,2] [,3] [,4]
## [1,]    1    4    7   10
## [2,]    2    5    8   11
## [3,]    3    6    9   12
x <- matrix(1:12, 3)
x
##      [,1] [,2] [,3] [,4]
## [1,]    1    4    7   10
## [2,]    2    5    8   11
## [3,]    3    6    9   12
x <- matrix(1:12, ncol = 4)
x
##      [,1] [,2] [,3] [,4]
## [1,]    1    4    7   10
## [2,]    2    5    8   11
## [3,]    3    6    9   12

Si la cantidad de datos no se puede acomodar de manera exacta en las dimensiones que estamos especificando, recibiremos una advertencia (“warning”) y probablemente no haya sucedido lo que esperamos (o se cortan los datos o se “reciclan”).

También es posible agregar renglones o columnas a matrices ya existentes con las funciones a continuación. Solo es cuestión de asegurarnos de que los objetos involucrados tienen el mismo tamaño en la dimensión que se pegarán: misma cantidad de renglones en el caso de rbind( ) y misma cantidad de columnas en el caso de cbind( ).

m <- matrix(1:9, 3, 3)

rbind(m, 101:103)
##      [,1] [,2] [,3]
## [1,]    1    4    7
## [2,]    2    5    8
## [3,]    3    6    9
## [4,]  101  102  103
cbind(m, 101:103)
##      [,1] [,2] [,3] [,4]
## [1,]    1    4    7  101
## [2,]    2    5    8  102
## [3,]    3    6    9  103

El subsetting o slicing de una matriz (2D) es similar al de los vectores (1D), pero ahora debemos especificar las coordenadas como [renglón, columna] en vez de solo [posición]. Cuando queremos hacer un filtro o selección solo de renglones o solo de columnas, pero no de ambas, simplemente dejamos en blanco la coordenada que no queremos filtrar. Algunos ejemplos a continuación.

Seleccionando solo un renglón y una columna:

x[3, ] # Un solo renglón
## [1]  3  6  9 12
x[, 2] # Una sola columna
## [1] 4 5 6

Nota cómo cuando el objeto resultante es de una sola dimensión R ya lo considera un vector y lo despliega de manera horizontal por cuestiones de legibilidad (ya no tiene como tal renglones o columnas sino posiciones). Es posible crear matrices de una sola columna y de esa manera R los desplegaría de manera vertical, pero eso requiere especificarse como tal. En el caso de arriba lo que obtenemos es un vector y en el de abajo es una matriz de una columna.

matrix(x[, 2], ncol = 1)
##      [,1]
## [1,]    4
## [2,]    5
## [3,]    6

Seleccionando una celda en específico:

x[3, 2]
## [1] 6

Seleccionando una submatriz:

x[1:3, 1:2]
##      [,1] [,2]
## [1,]    1    4
## [2,]    2    5
## [3,]    3    6

Un último ejemplo con la función array( ), solo como demostración de uso para un objeto 3D y para cerrar el tema de arreglos. Nota como en este caso nos crea un objeto con 3 renglones, 2 columnas y 2 “planos”.

z <- array(data = 1:12, dim = c(3, 2, 2)) # objeto con 3 renglones, 2 columnas y 2 “planos”
z
## , , 1
## 
##      [,1] [,2]
## [1,]    1    4
## [2,]    2    5
## [3,]    3    6
## 
## , , 2
## 
##      [,1] [,2]
## [1,]    7   10
## [2,]    8   11
## [3,]    9   12

3. Data frames

Los “data frames” son los objetos que típicamente se utilizan para guardar datos que leemos de un archivo, ya que estos no se limitan a un solo tipo de dato. Podemos pensar en los data frames como varios vectores de la misma longitud, pegados como columnas de una tabla. Estas son las reglas que tienen:

Data_frames

Construyamos un ejemplo a continuación. Empezaremos creando vectores de diferentes tipos de datos (pero de la misma longitud) y luego los consolidaremos en una tabla.

qbs <- c("Mahomes", "Garoppolo", "Brady", "Rodgers", "Brees")
teams <- c("Chiefs", "49ers", "Patriots", "Packers", "Saints")
ages <- c(24, 28, 42, 36, 41)
nfl <- data.frame(qbs, teams, ages)
nfl
##         qbs    teams ages
## 1   Mahomes   Chiefs   24
## 2 Garoppolo    49ers   28
## 3     Brady Patriots   42
## 4   Rodgers  Packers   36
## 5     Brees   Saints   41

Hasta ahora hemos estado desplegando todos los resultados en la consola. Sin embargo, en RStudio puede ser más fácil ver las tablas en una pestaña aparte. Una forma de lograr esto es con View( ). Otra forma es dar clic en el icono de tabla a la derecha del nombre de la variable en el panel de global environment. Esto segundo es en realidad un atajo que también envía el comando View( ) a la consola.

View(nfl)

Las formas de subsetting que vimos para matrices también aplican para data frames. Sin embargo los data frames tienen una forma adicional de seleccionar columnas. Las columnas de los data frames siempre tienen nombre. Esto se debe a que un caso de uso común es que cada columna represente una variable diferente (como veremos más delante) y es conveniente poder referirnos a ellas “por nombre” en vez de “por posición”, utilizando el operador $.

Revisa los siguientes ejemplos en RStudio.

Filtrando por número de columna y por nombre de columna, aprovechando la conveniencia del operador $:

nfl[, 3]
## [1] 24 28 42 36 41
nfl[, "ages"]
## [1] 24 28 42 36 41
nfl$ages
## [1] 24 28 42 36 41

Sin embargo, el operador $ solo funciona para seleccionar columnas de una en una, como si fueran variables independientes. Cuando queremos seleccionar varias, ocupamos enviarlas como vector (con nombres o posiciones).

Ve como las dos instrucciones abajo dan el mismo resultado. La ventaja de seleccionar columnas por nombre es que no es necesario contar el número de columna y que el código encontrará la columna deseada (mientras se siga llamando igual) sin importar si se agregan o eliminan columnas.

nfl[, c(1, 3)]
##         qbs ages
## 1   Mahomes   24
## 2 Garoppolo   28
## 3     Brady   42
## 4   Rodgers   36
## 5     Brees   41
nfl[, c("qbs", "ages")]
##         qbs ages
## 1   Mahomes   24
## 2 Garoppolo   28
## 3     Brady   42
## 4   Rodgers   36
## 5     Brees   41

Filtrando por número de renglón:

nfl[3,]
##     qbs    teams ages
## 3 Brady Patriots   42

También podemos referenciar celdas específicas si indicamos renglones y columnas:

nfl[c(1,3), 1:2]
##       qbs    teams
## 1 Mahomes   Chiefs
## 3   Brady Patriots

También podemos utilizar el operador $ para reemplazar el valor de una columna si la referenciamos y le asignamos valores nuevos, o incluso para agregar columnas nuevas si referenciamos una columna que no existe, de un data frame que ya está creado.

Ve el siguiente ejemplo en el que creamos la columna nueva cities (no existía previamente) en nuestra tabla de la nfl.

nfl$cities <- c("Kansas", "San Francisco", "New England",
"Green Bay", "New Orleans")

nfl
##         qbs    teams ages        cities
## 1   Mahomes   Chiefs   24        Kansas
## 2 Garoppolo    49ers   28 San Francisco
## 3     Brady Patriots   42   New England
## 4   Rodgers  Packers   36     Green Bay
## 5     Brees   Saints   41   New Orleans

De igual manera podemos eliminar columnas fácilmente, pero antes haremos una distinción entre dos palabras clave que a veces causan confusión: NA y NULL.

1. NA significa “not available” o “no disponible”. Es aconsejable que los datos faltantes estén identificados con esta palabra, dado que hay funciones que los pueden tomar en cuenta para hacer el cálculo de manera diferente.

2. NULL significa vacío, esto generalmente se utiliza para eliminar algún valor.

Veamos cómo funcionan en el caso de un data frame:

nfl$yards <- NA
nfl
##         qbs    teams ages        cities yards
## 1   Mahomes   Chiefs   24        Kansas    NA
## 2 Garoppolo    49ers   28 San Francisco    NA
## 3     Brady Patriots   42   New England    NA
## 4   Rodgers  Packers   36     Green Bay    NA
## 5     Brees   Saints   41   New Orleans    NA

La instrucción anterior no eliminó la columna, sino que la guardó con NAs, indicando que son datos faltantes. Normalmente solo tenemos algunos datos faltantes y como quiera podemos hacer uso de la información que tengamos, pero si falta toda la columna, a lo mejor vale la pena eliminarla.

nfl$yards <- NULL
nfl
##         qbs    teams ages        cities
## 1   Mahomes   Chiefs   24        Kansas
## 2 Garoppolo    49ers   28 San Francisco
## 3     Brady Patriots   42   New England
## 4   Rodgers  Packers   36     Green Bay
## 5     Brees   Saints   41   New Orleans

A diferencia del NA la instrucción anterior con NULL eliminó la columna.

Tipos de paréntesis en R

Ahora ya conocemos los diferentes tipos de paréntesis que utilizamos en R. A manera de recordatorio:

1. Cuando llamamos una función, enviamos los argumentos entre paréntesis redondos: function( )

2. Cuando hacemos subsetting de un arreglo, las coordenadas van entre paréntesis cuadrados: array[ ]

3. Cuando delimitamos un bloque de código, las instrucciones van entre corchetes: {code block}

Tidy data

Vale la pena introducir en este momento el concepto de “tidy data”. No todos los “data sets” que utilicemos estarán listos para analizarlos, sino que en la gran mayoría de los casos tendremos que acomodarlos y limpiarlos. Una guía para tener datos utilizables y un estándar que se trata de seguir en muchas bases de datos son los principios de “tidy data”.

Se considera tidy data los datos que cumplen con lo siguiente, y los que no, son messy data:

1. Cada columna es una variable (o campo)

2. Cada renglón es una observación (o registro)

3. Cada celda contiene un solo valor

Verificar que se cumplan estos principios suele ser uno de los primeros pasos en el acomodo y manipulación de datos (“data wrangling”) antes de utilizarlos en algún tipo de análisis.

Para más información y detalles puedes revisar:

Constantes y datasets

R cuenta ya con algunas constantes y con algunos data sets que ya están listos para usarse y sirven para hacer pruebas didácticas, sobre todo cuando queremos darnos una idea de cómo funciona algún paquete o alguna función que no hemos utilizado anteriormente. Incluso hay algunos paquetes que instalan algún dataset adicional y adecuado para el caso de uso de sus funciones, para hacer este tipo de pruebas.

Aquí algunas constantes ya predefinidas:

pi
## [1] 3.141593
letters
##  [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s"
## [20] "t" "u" "v" "w" "x" "y" "z"
LETTERS
##  [1] "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q" "R" "S"
## [20] "T" "U" "V" "W" "X" "Y" "Z"
month.abb
##  [1] "Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec"
month.name
##  [1] "January"   "February"  "March"     "April"     "May"       "June"     
##  [7] "July"      "August"    "September" "October"   "November"  "December"

Estas constantes son vectores y podemos manipularlas como tal:

letters[1:5]
## [1] "a" "b" "c" "d" "e"
month.abb[7:12]
## [1] "Jul" "Aug" "Sep" "Oct" "Nov" "Dec"

Para ver el listado de datasets que ya viene incluído en R base:

data()

Para ver la documentación de un dataset particular, por ejemplo, el de mtcars:

?mtcars
## starting httpd help server ... done

Para utilizar un dataset precargado, solo se ocupa referirlo por nombre. Observa como con la siguiente instrucción se carga en el global environment.

mtcars
##                      mpg cyl  disp  hp drat    wt  qsec vs am gear carb
## Mazda RX4           21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4
## Mazda RX4 Wag       21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4
## Datsun 710          22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1
## Hornet 4 Drive      21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1
## Hornet Sportabout   18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2
## Valiant             18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1
## Duster 360          14.3   8 360.0 245 3.21 3.570 15.84  0  0    3    4
## Merc 240D           24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2
## Merc 230            22.8   4 140.8  95 3.92 3.150 22.90  1  0    4    2
## Merc 280            19.2   6 167.6 123 3.92 3.440 18.30  1  0    4    4
## Merc 280C           17.8   6 167.6 123 3.92 3.440 18.90  1  0    4    4
## Merc 450SE          16.4   8 275.8 180 3.07 4.070 17.40  0  0    3    3
## Merc 450SL          17.3   8 275.8 180 3.07 3.730 17.60  0  0    3    3
## Merc 450SLC         15.2   8 275.8 180 3.07 3.780 18.00  0  0    3    3
## Cadillac Fleetwood  10.4   8 472.0 205 2.93 5.250 17.98  0  0    3    4
## Lincoln Continental 10.4   8 460.0 215 3.00 5.424 17.82  0  0    3    4
## Chrysler Imperial   14.7   8 440.0 230 3.23 5.345 17.42  0  0    3    4
## Fiat 128            32.4   4  78.7  66 4.08 2.200 19.47  1  1    4    1
## Honda Civic         30.4   4  75.7  52 4.93 1.615 18.52  1  1    4    2
## Toyota Corolla      33.9   4  71.1  65 4.22 1.835 19.90  1  1    4    1
## Toyota Corona       21.5   4 120.1  97 3.70 2.465 20.01  1  0    3    1
## Dodge Challenger    15.5   8 318.0 150 2.76 3.520 16.87  0  0    3    2
## AMC Javelin         15.2   8 304.0 150 3.15 3.435 17.30  0  0    3    2
## Camaro Z28          13.3   8 350.0 245 3.73 3.840 15.41  0  0    3    4
## Pontiac Firebird    19.2   8 400.0 175 3.08 3.845 17.05  0  0    3    2
## Fiat X1-9           27.3   4  79.0  66 4.08 1.935 18.90  1  1    4    1
## Porsche 914-2       26.0   4 120.3  91 4.43 2.140 16.70  0  1    5    2
## Lotus Europa        30.4   4  95.1 113 3.77 1.513 16.90  1  1    5    2
## Ford Pantera L      15.8   8 351.0 264 4.22 3.170 14.50  0  1    5    4
## Ferrari Dino        19.7   6 145.0 175 3.62 2.770 15.50  0  1    5    6
## Maserati Bora       15.0   8 301.0 335 3.54 3.570 14.60  0  1    5    8
## Volvo 142E          21.4   4 121.0 109 4.11 2.780 18.60  1  1    4    2

Algunas funciones para explorar el dataset:

View(mtcars)

head( ) y tail( ) nos muestran los primeros y últimos renglones de un data frame (respectivamente). Por default 6 renglones, pero podemos modificar la cantidad con el segundo argumento.

head(mtcars)
##                    mpg cyl disp  hp drat    wt  qsec vs am gear carb
## Mazda RX4         21.0   6  160 110 3.90 2.620 16.46  0  1    4    4
## Mazda RX4 Wag     21.0   6  160 110 3.90 2.875 17.02  0  1    4    4
## Datsun 710        22.8   4  108  93 3.85 2.320 18.61  1  1    4    1
## Hornet 4 Drive    21.4   6  258 110 3.08 3.215 19.44  1  0    3    1
## Hornet Sportabout 18.7   8  360 175 3.15 3.440 17.02  0  0    3    2
## Valiant           18.1   6  225 105 2.76 3.460 20.22  1  0    3    1
tail(mtcars, 5)
##                 mpg cyl  disp  hp drat    wt qsec vs am gear carb
## Lotus Europa   30.4   4  95.1 113 3.77 1.513 16.9  1  1    5    2
## Ford Pantera L 15.8   8 351.0 264 4.22 3.170 14.5  0  1    5    4
## Ferrari Dino   19.7   6 145.0 175 3.62 2.770 15.5  0  1    5    6
## Maserati Bora  15.0   8 301.0 335 3.54 3.570 14.6  0  1    5    8
## Volvo 142E     21.4   4 121.0 109 4.11 2.780 18.6  1  1    4    2

Si solo nos interesa conocer los nombres de las columnas de un data frame, para tener un listado de las variables con las que cuenta el data set, podemos utilizar la función names( ). También existen las funciones colnames( ) y rownames( ), pero se utilizan más para matrices, dado que ahí sí hay que especificar de qué dimensión queremos los nombres. En el caso de data frames casi no nos interesan los nombres de los renglones (suele ser solo un índice numérico) y la función names( ) es más corta que colnames( ).

names(mtcars)
##  [1] "mpg"  "cyl"  "disp" "hp"   "drat" "wt"   "qsec" "vs"   "am"   "gear"
## [11] "carb"

Si nos interesa saber las dimensiones del data frame, podemos observar el panel del ambiente y ver la cantidad de observaciones y de variables que indica. ¿Cuál de esos números son los renglones y cuál las columnas?

dim(mtcars)
## [1] 32 11
nrow(mtcars)
## [1] 32
ncol(mtcars)
## [1] 11

Otras funciones útiles para ver características del data frame como su estructura, tipos de datos en cada columna, valores faltantes y estadísticas resumen son str( ) y summary( ).

str(mtcars)
## 'data.frame':    32 obs. of  11 variables:
##  $ mpg : num  21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
##  $ cyl : num  6 6 4 6 8 6 8 4 4 6 ...
##  $ disp: num  160 160 108 258 360 ...
##  $ hp  : num  110 110 93 110 175 105 245 62 95 123 ...
##  $ drat: num  3.9 3.9 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 ...
##  $ wt  : num  2.62 2.88 2.32 3.21 3.44 ...
##  $ qsec: num  16.5 17 18.6 19.4 17 ...
##  $ vs  : num  0 0 1 1 0 1 0 1 1 1 ...
##  $ am  : num  1 1 1 0 0 0 0 0 0 0 ...
##  $ gear: num  4 4 4 3 3 3 3 4 4 4 ...
##  $ carb: num  4 4 1 1 2 1 4 2 2 4 ...
summary(mtcars)
##       mpg             cyl             disp             hp       
##  Min.   :10.40   Min.   :4.000   Min.   : 71.1   Min.   : 52.0  
##  1st Qu.:15.43   1st Qu.:4.000   1st Qu.:120.8   1st Qu.: 96.5  
##  Median :19.20   Median :6.000   Median :196.3   Median :123.0  
##  Mean   :20.09   Mean   :6.188   Mean   :230.7   Mean   :146.7  
##  3rd Qu.:22.80   3rd Qu.:8.000   3rd Qu.:326.0   3rd Qu.:180.0  
##  Max.   :33.90   Max.   :8.000   Max.   :472.0   Max.   :335.0  
##       drat             wt             qsec             vs        
##  Min.   :2.760   Min.   :1.513   Min.   :14.50   Min.   :0.0000  
##  1st Qu.:3.080   1st Qu.:2.581   1st Qu.:16.89   1st Qu.:0.0000  
##  Median :3.695   Median :3.325   Median :17.71   Median :0.0000  
##  Mean   :3.597   Mean   :3.217   Mean   :17.85   Mean   :0.4375  
##  3rd Qu.:3.920   3rd Qu.:3.610   3rd Qu.:18.90   3rd Qu.:1.0000  
##  Max.   :4.930   Max.   :5.424   Max.   :22.90   Max.   :1.0000  
##        am              gear            carb      
##  Min.   :0.0000   Min.   :3.000   Min.   :1.000  
##  1st Qu.:0.0000   1st Qu.:3.000   1st Qu.:2.000  
##  Median :0.0000   Median :4.000   Median :2.000  
##  Mean   :0.4062   Mean   :3.688   Mean   :2.812  
##  3rd Qu.:1.0000   3rd Qu.:4.000   3rd Qu.:4.000  
##  Max.   :1.0000   Max.   :5.000   Max.   :8.000

Otros paquetes pueden contener funciones que nos generen incluso más estadísticas resumen. Al 2021, R tiene más de 25 años de existencia y más de 18 mil paquetes en CRAN (sin contar los paquetes no-oficiales). Es imposible aprenderse todos los paquetes, más bien los irás conociendo con la práctica, conforme te enfrentes a problemas reales y les busques alguna solución.

Un ejemplo de una función útil para mostrar estadísticas resumen, de un paquete no-base es describe( ), del paquete psych( ).

#install.packages("psych")

library(psych)

describe(mtcars)
##      vars  n   mean     sd median trimmed    mad   min    max  range  skew
## mpg     1 32  20.09   6.03  19.20   19.70   5.41 10.40  33.90  23.50  0.61
## cyl     2 32   6.19   1.79   6.00    6.23   2.97  4.00   8.00   4.00 -0.17
## disp    3 32 230.72 123.94 196.30  222.52 140.48 71.10 472.00 400.90  0.38
## hp      4 32 146.69  68.56 123.00  141.19  77.10 52.00 335.00 283.00  0.73
## drat    5 32   3.60   0.53   3.70    3.58   0.70  2.76   4.93   2.17  0.27
## wt      6 32   3.22   0.98   3.33    3.15   0.77  1.51   5.42   3.91  0.42
## qsec    7 32  17.85   1.79  17.71   17.83   1.42 14.50  22.90   8.40  0.37
## vs      8 32   0.44   0.50   0.00    0.42   0.00  0.00   1.00   1.00  0.24
## am      9 32   0.41   0.50   0.00    0.38   0.00  0.00   1.00   1.00  0.36
## gear   10 32   3.69   0.74   4.00    3.62   1.48  3.00   5.00   2.00  0.53
## carb   11 32   2.81   1.62   2.00    2.65   1.48  1.00   8.00   7.00  1.05
##      kurtosis    se
## mpg     -0.37  1.07
## cyl     -1.76  0.32
## disp    -1.21 21.91
## hp      -0.14 12.12
## drat    -0.71  0.09
## wt      -0.02  0.17
## qsec     0.34  0.32
## vs      -2.00  0.09
## am      -1.92  0.09
## gear    -1.07  0.13
## carb     1.26  0.29

Conversión de estructuras de datos

Así como vimos funciones para convertir de un tipo de dato a otro también es posible convertir de un tipo de estructura a otra.

Considera el siguiente vector: al ser de una dimensión, no tiene renglones o columnas, solo posiciones y longitud total.

v1 <- 101:120
v1
##  [1] 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
## [20] 120
m1 <- as.matrix(v1)
m1
##       [,1]
##  [1,]  101
##  [2,]  102
##  [3,]  103
##  [4,]  104
##  [5,]  105
##  [6,]  106
##  [7,]  107
##  [8,]  108
##  [9,]  109
## [10,]  110
## [11,]  111
## [12,]  112
## [13,]  113
## [14,]  114
## [15,]  115
## [16,]  116
## [17,]  117
## [18,]  118
## [19,]  119
## [20,]  120

Observa como el default de as.matrix( ) en el caso de vectores, es convertirlos en matrices de una sola columna. Si quisiéramos especificar dimensiones diferentes, sería necesario utilizar directamente la función matrix( ) como le hicimos anteriormente.

m2 <- matrix(v1, ncol = 4)
m2
##      [,1] [,2] [,3] [,4]
## [1,]  101  106  111  116
## [2,]  102  107  112  117
## [3,]  103  108  113  118
## [4,]  104  109  114  119
## [5,]  105  110  115  120

También puedes ver como la consola de R indica entre paréntesis cuadrados la coordenada del elemento mostrado. En el caso de matrices muestra los renglones y las columnas mientras que en el caso de vectores muestra la posición del primer elemento que aparece en el renglón.

Los data frames también se pueden convertir a matrices, solo hay que considerar que mientras los data frames pueden tener varios tipos de datos, las matrices no, por ende puede suceder una conversión automática de tipo de datos también (coercing) al cual hay que estar atento.

m3 <- as.matrix(mtcars)
m3
##                      mpg cyl  disp  hp drat    wt  qsec vs am gear carb
## Mazda RX4           21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4
## Mazda RX4 Wag       21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4
## Datsun 710          22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1
## Hornet 4 Drive      21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1
## Hornet Sportabout   18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2
## Valiant             18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1
## Duster 360          14.3   8 360.0 245 3.21 3.570 15.84  0  0    3    4
## Merc 240D           24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2
## Merc 230            22.8   4 140.8  95 3.92 3.150 22.90  1  0    4    2
## Merc 280            19.2   6 167.6 123 3.92 3.440 18.30  1  0    4    4
## Merc 280C           17.8   6 167.6 123 3.92 3.440 18.90  1  0    4    4
## Merc 450SE          16.4   8 275.8 180 3.07 4.070 17.40  0  0    3    3
## Merc 450SL          17.3   8 275.8 180 3.07 3.730 17.60  0  0    3    3
## Merc 450SLC         15.2   8 275.8 180 3.07 3.780 18.00  0  0    3    3
## Cadillac Fleetwood  10.4   8 472.0 205 2.93 5.250 17.98  0  0    3    4
## Lincoln Continental 10.4   8 460.0 215 3.00 5.424 17.82  0  0    3    4
## Chrysler Imperial   14.7   8 440.0 230 3.23 5.345 17.42  0  0    3    4
## Fiat 128            32.4   4  78.7  66 4.08 2.200 19.47  1  1    4    1
## Honda Civic         30.4   4  75.7  52 4.93 1.615 18.52  1  1    4    2
## Toyota Corolla      33.9   4  71.1  65 4.22 1.835 19.90  1  1    4    1
## Toyota Corona       21.5   4 120.1  97 3.70 2.465 20.01  1  0    3    1
## Dodge Challenger    15.5   8 318.0 150 2.76 3.520 16.87  0  0    3    2
## AMC Javelin         15.2   8 304.0 150 3.15 3.435 17.30  0  0    3    2
## Camaro Z28          13.3   8 350.0 245 3.73 3.840 15.41  0  0    3    4
## Pontiac Firebird    19.2   8 400.0 175 3.08 3.845 17.05  0  0    3    2
## Fiat X1-9           27.3   4  79.0  66 4.08 1.935 18.90  1  1    4    1
## Porsche 914-2       26.0   4 120.3  91 4.43 2.140 16.70  0  1    5    2
## Lotus Europa        30.4   4  95.1 113 3.77 1.513 16.90  1  1    5    2
## Ford Pantera L      15.8   8 351.0 264 4.22 3.170 14.50  0  1    5    4
## Ferrari Dino        19.7   6 145.0 175 3.62 2.770 15.50  0  1    5    6
## Maserati Bora       15.0   8 301.0 335 3.54 3.570 14.60  0  1    5    8
## Volvo 142E          21.4   4 121.0 109 4.11 2.780 18.60  1  1    4    2
m4 <- as.matrix(nfl)
m4
##      qbs         teams      ages cities         
## [1,] "Mahomes"   "Chiefs"   "24" "Kansas"       
## [2,] "Garoppolo" "49ers"    "28" "San Francisco"
## [3,] "Brady"     "Patriots" "42" "New England"  
## [4,] "Rodgers"   "Packers"  "36" "Green Bay"    
## [5,] "Brees"     "Saints"   "41" "New Orleans"

Observa como m3 es una matriz numérica: dado que mtcars contenía puros números, se pudo respetar ese tipo de dato. Por otro lado, m4 es una matriz de texto: aunque nfl tenía una columna numérica, tenía otras de texto y tuvo que utilizar el tipo de dato más general. Es más fácil convertir los números a texto, así que con un dato de texto se convierte toda la matriz a texto.