7.1 Índices

Usar índices para obtener subconjuntos es el procedimiento más universal en R, pues funciona para todas las estructuras de datos.

Un índice en R representa una posición. Cuando usamos índices le pedimos a R que extraiga de una estructura los datos que se encuentran en una o varias posiciones específicas dentro de ella.

A diferencia de la mayoría de los lenguajes de programación, los índices en R empiezan en 1, no en 0. El índice del primer elemento de una estructura de datos siempre es 1, el segundo 2, y así sucesivamente.

Un aspecto muy importante de este procedimiento es que, para data frames y listas, cuando extraemos un subconjunto de un objeto usando corchetes, obtenemos como resultado un objeto de la misma clase que el objeto original. Si extraemos un subconjunto de un data frame, obtenemos un vector; y si extraemos de una lista, obtenemos una lista.

El uso de índices tiene además otras características particulares para las distintas estructuras de datos, así que veremos este procedimiento para cada una de ellas.

7.1.1 Vectores

Empecemos creando un vector que contiene los nombres de distintos niveles educativos.

nivel <- c("Preescolar", "Primaria", "Secundaria", "Educación Media Superior",
           "Educación Superior")

nivel
## [1] "Preescolar"               "Primaria"                
## [3] "Secundaria"               "Educación Media Superior"
## [5] "Educación Superior"

Este es un vector de largo igual a cinco.

length(nivel)
## [1] 5

¿Cómo obtendríamos el tercer elemento de este vector usando índices? ¿O del primer al cuarto elemento? ¿O el segundo y quinto elemento?

Para obtener subconjuntos con índices escribimos corchetes [] después del nombre de un objeto. Dentro de los corchetes escribimos el o los números que corresponden a la posición que nos interesa extraer del objeto.

Por ejemplo:

  • objeto[3]
  • lista[4:5]
  • dataframe[c(2, 7), ]

Entonces, para extraer el tercer elemento de nuestro vector nivel hacemos lo siguiente.

nivel[3]
## [1] "Secundaria"

Para extraer del primer al cuarto elemento de un vector, usamos un vector con una secuencia numérica del 1 al 4 creada con :.

nivel[1:4]
## [1] "Preescolar"               "Primaria"                
## [3] "Secundaria"               "Educación Media Superior"

Sin embargo, si intentamos extraer el segundo y quinto elemento del vector nivel corriendo lo siguiente, obtendremos un error.

nivel[2, 5]
## Error in nivel[2, 5]: incorrect number of dimensions

¿Porqué no ha funcionado lo anterior?

El mensaje de error nos da una pista muy importante. Al usar una coma dentro de los corchetes estamos dando la instrucción a R de buscar los índices solicitados en más de una dimensión. El número antes de la coma será buscado en la primera dimensión del objeto, y el segundo número, en su segunda dimensión.

Entonces, al llamar nivel[2, 5], lo que estamos pidiendo es que R extraiga el elemento que se encuentra en la posición 2 de la primera dimensión del vector, y el elemento en la posición 5 de su segunda dimensión. Como los vectores son unidimensionales, es imposible cumplir esta instrucción y se produce un error.

Recuerda que en R, un número sencillo es también un vector, por lo tanto, cuando escribimos vector[3], en realidad estamos dando como índice un vector que contiene al número 3.

Por lo tanto, si deseamos extraer elementos en posiciones no consecutivas, debemos usar vectores generados con c(). De este modo damos un vector, de más de un número de largo al corchete, pero todos se encuentran en una misma dimensión.

Aplicando lo anterior, si escribimos dentro de los corchetes c(2, 5), entonces tendremos éxito al extraer el segundo y quinto elemento de nivel.

nivel[c(2, 5)]
## [1] "Primaria"           "Educación Superior"

Para estructuras de dos dimensiones, como son matrices y data frames, el primer vector de un índice, antes de una coma, es la posición en los renglones y el segundo es la posición las columnas.

Obtener subconjuntos por renglones y columnas es un tipo de operación muy común al trabajar con data frames y matrices.

7.1.2 Data frames

Creamos un data frame llamado mi_df.

mi_df <- data.frame("nombre" = c("Armando", "Elsa", "Ignacio", "Olga"),
                    "edad" = c(20, 24, 22, 30),
                    "sexo" = c("H", "M", "M", "H"),
                    "grupo" = c(0, 1, 1, 0))

# Resultado
mi_df
##    nombre edad sexo grupo
## 1 Armando   20    H     0
## 2    Elsa   24    M     1
## 3 Ignacio   22    M     1
## 4    Olga   30    H     0

Usamos dim() para confirmar que nuestro objeto tiene dos dimensiones: tres renglones y tres columnas.

dim(mi_df)
## [1] 4 4

Si usamos un índice con un sólo número, extraemos una columna completa, con todos sus renglones.

mi_df[1]
##    nombre
## 1 Armando
## 2    Elsa
## 3 Ignacio
## 4    Olga

Si usamos un vector, sin comas, obtenemos varias columnas.

mi_df[c(1, 3)]
##    nombre sexo
## 1 Armando    H
## 2    Elsa    M
## 3 Ignacio    M
## 4    Olga    H

Al usar comas, el vector antes de la coma nos devolverá un renglón completo.

mi_df[3,]
##    nombre edad sexo grupo
## 3 Ignacio   22    M     1

Nota que si dejamos vació el espacio después de la coma, se nos devuelven todas las columnas del data frame.

Si el espacio que dejamos vacío es el que se encuentra después de la coma, obtenemos columnas. Esto es equivalente a usar un solo vector dentro de los corchetes.

mi_df[ ,1]
## [1] Armando Elsa    Ignacio Olga   
## Levels: Armando Elsa Ignacio Olga

Al combinar índices para renglones y columnas, obtenemos los datos que se encuentran en una posición específica.

Por ejemplo, el dato en el tercer renglón y la tercer columna.

mi_df[3, 3]
## [1] M
## Levels: H M

El segundo y tercer dato de la tercera columna.

mi_df[2:3, 3]
## [1] M M
## Levels: H M

El cuarto renglón de la tercera y cuarta columna.

mi_df[4, 3:4]
##   sexo grupo
## 4    H     0

También podemos usar vectores de más de un número. Por ejemplo, los datos en en el primer y segundo renglón, y en la segunda y cuarta columna.

mi_df[1:2, c(2, 4)]
##   edad grupo
## 1   20     0
## 2   24     1

Por último, en todos los casos anteriores, hemos obtenido como resultado un data frame.

sub_df <- mi_df[1:2, c(2, 4)]

class(sub_df)
## [1] "data.frame"

Si damos un índice inválido para las columnas, es decir, un número de columna que no exista, se nos devuelve un renglón.

Intentemos obtener la séptima columna de mi_df.

mi_df[7]
## Error in `[.data.frame`(mi_df, 7): undefined columns selected

Sin embargo, para los renglones simplemente se nos devuelve NA.

mi_df[7, ]
##    nombre edad sexo grupo
## NA   <NA>   NA <NA>    NA

7.1.3 Matrices

El procedimiento anterior para data frames funciona de la misma manera para las matrices, con una excepción.

Si usamos como índice un sólo número, entonces obtendremos el valor que se encuentre en esa posición, contando celdas de arriba a abajo y de izquierda a derecha.

Creamos una matriz con 4 renglones y dos columnas.

mi_matriz <- matrix(1:8, nrow = 4)

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

Si damos como índice el número 8, R no intentará devolvernos la octava columna de la matriz, sino la octava celda.

mi_matriz[8]
## [1] 8

Fuera de este caso, los índices de renglones y columna tienen el mismo comportamiento que en un data frame.

# Tercer renglón
mi_matriz[3, ]
## [1] 3 7
# Segunda columna
mi_matriz[ ,2]
## [1] 5 6 7 8
# Tercer renglón y segunda columna
mi_matriz[3, 2]
## [1] 7

Nota que en este caso obtenemos vectores al extraer un subconjunto.

7.1.4 Arrays

Para objetos de tres o más dimensiones se siguen las mismas reglas que con las matrices, aunque ya no es tan fácil hablar de renglones y columnas.

Creamos un array de cuatro dimensiones.

mi_array <- array(data = 1:16, dim = c(2, 2, 2, 2))

Veamos nuestro resultado y comprobamos con dim() su número de dimensiones.

mi_array
## , , 1, 1
## 
##      [,1] [,2]
## [1,]    1    3
## [2,]    2    4
## 
## , , 2, 1
## 
##      [,1] [,2]
## [1,]    5    7
## [2,]    6    8
## 
## , , 1, 2
## 
##      [,1] [,2]
## [1,]    9   11
## [2,]   10   12
## 
## , , 2, 2
## 
##      [,1] [,2]
## [1,]   13   15
## [2,]   14   16
# Comprobamos el número de dimensiones de nuestro objeto
dim(mi_array)
## [1] 2 2 2 2

Intentemos extraer varios subconjuntos, sólo para ilustrar cómo funcionan los índices con arrays.

mi_array[1, , , ]
## , , 1
## 
##      [,1] [,2]
## [1,]    1    5
## [2,]    3    7
## 
## , , 2
## 
##      [,1] [,2]
## [1,]    9   13
## [2,]   11   15
mi_array[1, 2, , ]
##      [,1] [,2]
## [1,]    3   11
## [2,]    7   15
mi_array[1, 2, 1, ]
## [1]  3 11
mi_array[1, 2, 1, 2]
## [1] 11

Nota que como resultados obtenemos matrices, a menos que hagamos una extraigamos el contenido de una sola celda.