Principales objetos en R

La información que manipulamos en R se estructura en forma de objetos. Para trabajar con R resulta importante conocer los principales tipos de objetos y sus propiedades básicas. En general, cada tipo de objeto viene definido por una serie de atributos. Las funciones genéricas (como por ejemplo summary o plot) reconocen estos atributos y llevan a cabo distintos tipos de acciones en función del tipo de objeto. Aquí nos vamos a centrar solo en los objetos más utilizados: vectores, matrices, listas, data frames y factores.

Vectores

Algunos comandos para generar vectores

Para encadenar dos vectores podemos usar el comando c(). Los escalares son, a todos los efectos, vectores de longitud 1:

x <- c(2, 4, 6)
y <- c(3, 7)
c(x, y)
## [1] 2 4 6 3 7

Para generar sucesiones o vectores de valores repetidos podemos usar los siguientes comandos:

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

Reciclaje

Es muy importante para operar con vectores tener en cuenta la regla del reciclaje: si usamos vectores que no alcanzan la dimensión adecuada para ciertas operaciones, R automáticamente recicla el vector (repite los valores) hasta llegar a la dimensión requerida.

3 + c(1, 2, 3)
## [1] 4 5 6
c(1, 2) + c(7, 8, 9)
## Warning: longitud de objeto mayor no es múltiplo de la longitud de uno
## menor
## [1]  8 10 10

Por una parte, esta propiedad es peligrosa ya que podemos cometer errores sin darnos cuenta. La parte positiva es que muchas veces permite ahorrar código. En el segundo de los ejemplos anteriores vemos que si la dimensión del vector no es un divisor de la dimensión adecuada, recibimos un mensaje de aviso (pero se sigue aplicando el reciclaje y la operación se lleva a cabo).

Valores especiales

Las expresiones NA, NaN, Inf, NULL están reservadas para los valores especiales Not Available, Not a Number, Infinity y Null, respectivamente. Para entender cómo opera R con estos valores, observa los ejemplos siguientes:

x <- c(NA, NaN, Inf, 0, 3, NULL)
1/x
## [1]     NA    NaN 0.0000    Inf 0.3333
x - x
## [1]  NA NaN NaN   0   0
1/x - (x - x)
## [1]     NA    NaN    NaN    Inf 0.3333

El valor Null corresponde a vacío y es ignorado. Puede ser útil sin embargo si queremos crear un objeto que luego vamos a ir completando poco a poco.

Selección de las coordenadas de un vector

Se usan corchetes para generar subvectores formados por algunas de las coordenadas de un vector:

x <- (1:5)^2
x
## [1]  1  4  9 16 25
x[2]
## [1] 4
x[c(2, 5)]
## [1]  4 25

Pueden utilizarse valores negativos dentro del corchete para eliminar coordenadas:

x[-c(2, 5)]
## [1]  1  9 16

También se pueden usar operaciones lógicas para seleccionar las coordenadas que cumplen cierta condición. El comando which se usa para saber los índices de las coordenadas que cumplen la condición:

x <- (1:5)^2
x
## [1]  1  4  9 16 25
x[x > 15]
## [1] 16 25
which(x > 15)
## [1] 4 5

Matrices

Las matrices son también vectores pero con dos atributos adicionales: número de filas y número de columnas. Sin embargo, los vectores no son matrices con una fila o con una columna. Para crear una matriz:

matrix(1:3, nrow = 2, ncol = 3)
##      [,1] [,2] [,3]
## [1,]    1    3    2
## [2,]    2    1    3

El primer argumento es un vector que incluye los elementos de la matriz y los otros dos corresponden al número de filas y columnas. Los elementos se van colocando por columnas. Observa cómo se ha aplicado la regla del reciclaje en el ejemplo anterior.

Veamos qué ocurre al sumar un vector y una matriz:

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

Tal vez es conveniente explicar paso a paso el resultado de la operación anterior:

En el ejemplo siguiente, la matriz es de nuevo considerada como un vector. Se seleccionan todas las entradas de la matriz mayores que seis y se devuelven en forma de vector. Los índices correspondientes se refieren también a la matriz considerada como vector.

x <- matrix(5:8, 3, 4)
x
##      [,1] [,2] [,3] [,4]
## [1,]    5    8    7    6
## [2,]    6    5    8    7
## [3,]    7    6    5    8
x[x > 6]
## [1] 7 8 7 8 7 8
which(x > 6)
## [1]  3  4  7  8 11 12

Selección de entradas de una matriz

Usando corchetes es posible extraer submatrices. Dentro del corchete, separadas por una coma, se indican las filas y columnas que queremos extraer (o eliminar si usamos números negativos). Si no se pone nada antes o después de la coma se extraen todas las filas o columnas, respectivamente:

x
##      [,1] [,2] [,3] [,4]
## [1,]    5    8    7    6
## [2,]    6    5    8    7
## [3,]    7    6    5    8
x[1, 2]
## [1] 8
x[, 3]
## [1] 7 8 5
x[3, -1]
## [1] 6 5 8

Pegar vectores para formar matrices

Con los comandos cbind y rbind se pueden pegar varios vectores para formar una matriz. Si usamos cbind cada vector será una columna de la matriz formada. Con rbind será una fila:

y <- 1:3
z <- 4:6
cbind(y, z)
##      y z
## [1,] 1 4
## [2,] 2 5
## [3,] 3 6
rbind(y, z)
##   [,1] [,2] [,3]
## y    1    2    3
## z    4    5    6

Cómo aplicar funciones a cada fila o columna de una matriz

Resulta bastante frecuente la necesidad de aplicar una función a cada una de las filas o columnas de una matriz. Para ello se usa el comando apply(). Este comando tiene tres argumentos:

En el siguiente ejemplo se calculan las medias de cada columna de x. Compara el resultado de apply con el de aplicar directamente el comando sobre la matriz. ¿Qué ocurre en este útimo caso? Como mean opera sobre vectores, al escribir mean(x) se considera la matriz como un vector y se calcula el promedio de todas sus entradas.

x
##      [,1] [,2] [,3] [,4]
## [1,]    5    8    7    6
## [2,]    6    5    8    7
## [3,]    7    6    5    8
mean(x)
## [1] 6.5
apply(x, 2, mean)
## [1] 6.000 6.333 6.667 7.000

En el ejemplo siguiente se ordenan de menor a mayor cada una de las filas de una matriz. Observa con atención la dimensión de la matriz resultante:

x
##      [,1] [,2] [,3] [,4]
## [1,]    5    8    7    6
## [2,]    6    5    8    7
## [3,]    7    6    5    8
apply(x, 1, sort)
##      [,1] [,2] [,3]
## [1,]    5    5    5
## [2,]    6    6    6
## [3,]    7    7    7
## [4,]    8    8    8

Si al aplicar la función sobre una columna o fila el resultado es otro vector, el resultado de apply será una matriz. En este caso, los resultados de la aplicación a cada columna o fila son las columnas de la matriz resultante.

Operaciones más habituales con matrices

En este apartado se resumen los comandos necesarios para llevar a cabo la operaciones con matrices más habituales:

Listas

Una lista es un vector de objetos de tipos distintos, que conviene agrupar en la misma estructura por diversas razones (por ejemplo, son un conjunto de resultados de un análisis estadístico de un conjunto de datos). Intuitivamente, es como una caja en la que se ponen objetos relacionados. Es importante comprender sus propiedades porque muchas funciones de R devuelven los resultados en forma de lista. Para crearlas se usa el comando list. En el siguiente ejemplo creamos una lista llamada milista con tres elementos llamados nombre, no.hijos y edades.hijos (este último es un vector de longitud 3):

milista <- list(nombre = "Pepe", no.hijos = 3, edades.hijos = c(4, 7, 9))

La estructura de una lista (los objetos que contiene la caja y de qué tipo son) se puede conocer con el comando str():

str(milista)
## List of 3
##  $ nombre      : chr "Pepe"
##  $ no.hijos    : num 3
##  $ edades.hijos: num [1:3] 4 7 9

Extraer elementos de una lista

Para extrer un elemento de una lista se usa nombre_lista$nombre_objeto si los elementos de la lista tienen nombre. También se puede usar un doble corchete y el número de orden del objeto dentro de la lista:

milista$nombre
## [1] "Pepe"
milista[[1]]
## [1] "Pepe"
milista$edades.hijos[2]
## [1] 7

En el último ejemplo anterior hemos extraído el último elemento (que era un vector) y, dentro de este, la segunda coordenada. Para reflexionar sobre la diferencia entre un único corchete y un doble corchete, piensa en las siguientes cuestiones:

Data frames

Un data frame es la estructura que se usa en R para los ficheros de datos correspondientes a una serie de variables medidas en cada sujeto o unidad bajo estudio. Intuitivamente podemos ver un data frame como una matriz con entradas que pueden ser de distintos tipos (números, palabras, etc.). Técnicamente son listas cuyos elementos son vectores de la misma longitud.

Para crearlos se utiliza el comando data.frame. En el siguiente ejemplo creamos uno llamado mifichero con dos vectores llamados edad y grupo. Los vectores (variables) son de la misma longitud pero son heterogéneos en el sentido de que el primero contiene números y el segundo letras.

x <- 7:9
y <- c("a", "b", "c")
mifichero <- data.frame(edad = x, grupo = y)
mifichero
##   edad grupo
## 1    7     a
## 2    8     b
## 3    9     c

Dado que los data frames son un tipo particular de listas, podemos aplicarles todos los comandos que hemos introducido en la sección anterior:

str(mifichero)
## 'data.frame':    3 obs. of  2 variables:
##  $ edad : int  7 8 9
##  $ grupo: Factor w/ 3 levels "a","b","c": 1 2 3
mifichero$edad
## [1] 7 8 9
mifichero[[2]]
## [1] a b c
## Levels: a b c

Al mismo tiempo, también admiten algunos de los comandos que se aplican a las matrices. Para extraer todas las variables correspondientes a la segunda observación (la segunda fila del fichero) podemos escribir:

mifichero[2, ]
##   edad grupo
## 2    8     b

Aplicación de un comando a cada variable de un data frame

Si queremos aplicar el mismo comando a todas las variables de un fichero podemos usar dos comandos, lapply y sapply, que difieren en la estructura que tiene el resultado:

Como ejemplo tomamos el fichero faithful que contiene datos de duración y tiempo de espera entre erupciones del geyser Old faithful en Yellowstone. Si queremos obtener las principales medidas descriptivas de cada una de las dos variables del fichero:

sapply(faithful, summary)
##         eruptions waiting
## Min.         1.60    43.0
## 1st Qu.      2.16    58.0
## Median       4.00    76.0
## Mean         3.49    70.9
## 3rd Qu.      4.45    82.0
## Max.         5.10    96.0
lapply(faithful, summary)
## $eruptions
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    1.60    2.16    4.00    3.49    4.45    5.10 
## 
## $waiting
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    43.0    58.0    76.0    70.9    82.0    96.0

Observa que los resultados son los mismos, pero estructurados de manera diferente.

Factores

Los factores son las estructuras que se utilizan para manejar las variables cualitativas en los análisis estadísticos. Se pueden contemplar como un vector al que se añade un poco más de información consistente en los distintos valores presentes en el vector, llamados niveles. Se crean usando el comando factor(). Veamos un ejemplo:

x <- c(2, 2, 3, 4, 2, 5)
x
## [1] 2 2 3 4 2 5
xfactor <- factor(x)
xfactor
## [1] 2 2 3 4 2 5
## Levels: 2 3 4 5

Aplicar una función para cada nivel de un factor

El fichero iris contiene los famosos datos de lirios de Fisher con medidas de la longitud y anchura del sépalo y pétalo de 150 lirios correspondientes a tres especies. Veamos las primeras observaciones del fichero:

head(iris)
##   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

La última variable es un factor que indica la especie a la que corresponde cada observación:

iris$Species
##   [1] setosa     setosa     setosa     setosa     setosa     setosa    
##   [7] setosa     setosa     setosa     setosa     setosa     setosa    
##  [13] setosa     setosa     setosa     setosa     setosa     setosa    
##  [19] setosa     setosa     setosa     setosa     setosa     setosa    
##  [25] setosa     setosa     setosa     setosa     setosa     setosa    
##  [31] setosa     setosa     setosa     setosa     setosa     setosa    
##  [37] setosa     setosa     setosa     setosa     setosa     setosa    
##  [43] setosa     setosa     setosa     setosa     setosa     setosa    
##  [49] setosa     setosa     versicolor versicolor versicolor versicolor
##  [55] versicolor versicolor versicolor versicolor versicolor versicolor
##  [61] versicolor versicolor versicolor versicolor versicolor versicolor
##  [67] versicolor versicolor versicolor versicolor versicolor versicolor
##  [73] versicolor versicolor versicolor versicolor versicolor versicolor
##  [79] versicolor versicolor versicolor versicolor versicolor versicolor
##  [85] versicolor versicolor versicolor versicolor versicolor versicolor
##  [91] versicolor versicolor versicolor versicolor versicolor versicolor
##  [97] versicolor versicolor versicolor versicolor virginica  virginica 
## [103] virginica  virginica  virginica  virginica  virginica  virginica 
## [109] virginica  virginica  virginica  virginica  virginica  virginica 
## [115] virginica  virginica  virginica  virginica  virginica  virginica 
## [121] virginica  virginica  virginica  virginica  virginica  virginica 
## [127] virginica  virginica  virginica  virginica  virginica  virginica 
## [133] virginica  virginica  virginica  virginica  virginica  virginica 
## [139] virginica  virginica  virginica  virginica  virginica  virginica 
## [145] virginica  virginica  virginica  virginica  virginica  virginica 
## Levels: setosa versicolor virginica

Supongamos que queremos calcular la media de las lóngitudes de los pétalos para cada una de las tres especies. Para ello podemos usar la funcion tapply(), que tiene tres argumentos:

tapply(iris$Petal.Length, iris$Species, mean)
##     setosa versicolor  virginica 
##      1.462      4.260      5.552