Si te has pasado por este blog en las últimas semanas y has consultado la entrada sobre como empezar con R en RStudio seguro que ya tienes R instalado y ya te has familiarizado con sus paneles y con lo que es un script. Si no, te invito a que te pases antes por allí y le eches un vistazo.
Ahora es momento de encontrarnos con aquellos elementos que conforman la base de R. Los objetos.
Pero ¿qué son los objetos? ¿Cuántos tipos diferentes hay? ¿Cómo podemos trabajar con ellos?
¿Me dejas que te cuente?
¿Qué son los objetos?
Supongo que alguien con conocimientos avanzados de informática tendría una forma muy concreta de definir lo que es un objeto. Pero como yo no soy esa persona y lo más probable es que meta la pata si lo intento, déjame que te lo explique a mi manera, desde la estadística y las matemáticas.
Desde ese punto de vista, los objetos en R son contenedores, con una cierta estructura, que nos permiten almacenar valores. En particular, lo que haremos será escoger un nombre y asignarle los valores que queremos almacenar en él. Para ello, como ya vimos en la entrada anterior, vamos a usar el símbolo de la asignación que se construye con el símbolo “menor que” < y un guión medio -: <-
Por ver un ejemplo muy sencillo, piensa que quieres guardar el nombre, la edad y la altura de una persona.
> nombre <- "Ana"
> edad <- 23
> estatura <- 1.67
Así hemos creado tres objetos que habrán aparecido en tu pestaña environment sin dar ninguna respuesta en la consola. Prueba ahora a escribir los nombres de estos objetos en la consola y ejecutarlos.
> nombre
## [1] "Ana"
> edad
## [1] 23
> estatura
## [1] 1.67
¿Qué pasa? ¿Devuelve los valores? ¿Cómo lo hace? ¿Aparece algo antes del valor? Quédate con esos corchetes, que nos serán útiles.
Este tipo de objetos que acabamos de crear y que son super sencillos se llaman variables, pero no son el único tipo, por supuesto, veamos más:
Tipos de objetos
Los tipos de objetos básicos que podemos crear en R son:
- variables, cuando sólo tengo que guardar un valor (como hemos visto en el ejemplo),
- vectores, cuando tengo que guardar varios valores juntos. Las variables serían un caso particular de los vectores.
- matrices, arrays o bancos de datos, cuando tengo muchos valores pero, además tienen una estructura en forma de “capas” (luego te explico esto un poco mejor).
- listas, cuando se trata de guardar varias de las anteriores estructuras juntas.
A la hora de crear alguno de estos objetos lo que necesitaremos es usar funciones. Recordemos que en la entrada anterior dijimos brevemente que una función es también un tipo muy especial de objeto que tiene un nombre y que lo que hace es ejecutar una acción a partir de los argumentos que le añadimos entre paréntesis.
Veamos algunas según los objetos que queramos crear.
Creando un vector
En el caso de la creación de objetos la función más sencilla es la que se usa para crear un vector y que tiene como nombre “c” (de concatenar, unir o enlazar dos o más cosas). Los argumentos que le introduciremos a c serán los valores que queremos “enlazar” y que, una vez unidos, formarán un vector.
Siguiendo con el ejemplo inicial, imagina que queremos almacenar la información: nombre, estatura y altura, pero de varias personas. Fíjate:
> nombre <- c("Ana", "Adriana", "Julio", "Clara", "Andrés")
> edad <- c(23, 24, 26, 21, 28)
> estatura <- c(1.67,1.60, 1.78, 1.70, 1.83)
Al ejecutar estas ordenes, fíjate en el enviroment. ¿Qué ha aparecido? ¿Qué diferencia hay con lo que había antes?
Captura de pantalla con el enviroment después de haber creado los vectores nombre, edad y estatura
Lo primero en lo que debes fijarte es en que hemos «machacado» el valor de la primera vez que creamos estos objetos. Tienen el mismo nombre pero nueva información. No puedes tener dos objetos con el mismo nombre así que, cuidado con esto.
Ahora, si lo miras con detalle verás que aparecen los valores que hemos introducido pero, antes de ellos, aparece una indicación que dice “num” en edad y estatura y “chr” en los nombres. Quédate con esto, que luego lo explicamos.
Además, aparece entre corchetes la expresión 1:5. Esto nos está diciendo que se trata de un vector con 5 valores y que estos valores aparecen en las posiciones 1, 2, 3, 4 y 5… es más, te invito a que ejecutes la orden 1:5 directamente en la consola de R. ¿Qué ha pasado?
> 1:5
## [1] 1 2 3 4 5
Además de saber como el enviroment te indica el número de valores que tiene un vector, acabas de descubrir una forma de crear vectores en forma de secuencia. Siempre que pongas dos valores numéricos con el símbolo “:” en medio, R creará un vector que irá del primer valor al último avanzando de 1 en 1 (hacia arriba o hacia abajo) pero sin pasarse nunca del último valor. Prueba:
> 2.1:6.5
## [1] 2.1 3.1 4.1 5.1 6.1
> pi:0
## [1] 3.1415927 2.1415927 1.1415927 0.1415927
¿Cuál es el último número en estas dos secuencias? ¿Te imaginas porque se ha quedado ahí? ¿Cuál habría sido el siguiente número si hubiese continuado?
Lo malo de estas secuencias es que sólo van de 1 en 1 pero existen otras formas de crear secuencias más completas como es el caso de la función seq. Con esta función puedes ir de un valor a otro con saltos de la longitud que te interese, o decidir cuantos valores quieres en total. Por ejemplo:
> seq(from = 2.1, to = 6.5, by = 0.1)
## [1] 2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.9 3.0 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9
## [20] 4.0 4.1 4.2 4.3 4.4 4.5 4.6 4.7 4.8 4.9 5.0 5.1 5.2 5.3 5.4 5.5 5.6 5.7 5.8
## [39] 5.9 6.0 6.1 6.2 6.3 6.4 6.5
> seq(from = 2.1, to = 6.5, by = 0.2)
## [1] 2.1 2.3 2.5 2.7 2.9 3.1 3.3 3.5 3.7 3.9 4.1 4.3 4.5 4.7 4.9 5.1 5.3 5.5 5.7
## [20] 5.9 6.1 6.3 6.5
> seq(from = 2.1, to = 6.5, length = 10)
## [1] 2.100000 2.588889 3.077778 3.566667 4.055556 4.544444 5.033333 5.522222
## [9] 6.011111 6.500000
Bueno, pero me he liado contandote lo de las secuencias y yo quería explicarte porque el 1:5 aparece entre corchetes, porque digo que un vector tiene posiciones y como esa idea nos puede ayudar a acceder a los valores individuales que hay dentro de vector. Vamos a ello:
Como acceder a los datos de un vector
Cuando digo que un vector tiene posiciones yo siempre me imagino un pastillero de esos que van de lunes a domingo y que en cada día tienen un contenedor para la medicación de ese día. Así, la posición 1 se corresponde con una puertecita (la del lunes) y cuando abro esa puerta tendré ciertos elementos (medicación del lunes). Para abrir la puertecita en R y descubrir lo que el vector tiene en esa posición, lo que tengo que hacer es escribir el nombre del vector y justo a continuación abro corchete y pongo el valor de la posición a la que quiero acceder. Ponlo a prueba
> edad[2]
## [1] 24
> nombre[2]
## [1] "Adriana"
Incluso, si quieres, puedes abrir dos puertas a la vez. Para eso puedes usar un vector que indique las posiciones. Imagina que quieres abrir la posición 1 y la 3:
> edad[c(1,3)]
## [1] 23 26
> nombre[c(1,3)]
## [1] "Ana" "Julio"
A estos vectores que nos dicen las posiciones que queremos abrir los llamamos vectores indices y te prometo que volvermos a ellos en próximas entradas porque son muy muy importantes en el lenguaje R. Pero sigamos ahora porque hay algo que te quiero contar antes de pasar a hablar de más tipos de objetos. ¿Qué tipo de elementos podemos meter en esas puertecitas del vector?
Si vas un poco más arriba, veras que te he dicho que te quedaras con lo de “num” y “chr”. Esto tiene mucho que ver con lo que te voy a contar ahora.
Desde el punto de vista de la estadística te diré que esos valores que vamos a almacenar serán seguramente datos de algún tipo así que déjame que te refresque la memoria.
Refrescando la memoria: Datos y variables
Cuando hablamos de datos, nos estamos refiriendo a ciertos valores observados para una variable en los elementos de una muestra.
Si quieres recordar lo que era una muestra puedes consultar la entrada Población y muestra en la que lo cuento.
Cuando hablamos de variables, por otro lado, nos estamos refiriendo a alguna característica de la población que queremos medir y que observamos, como ya hemos dicho, en los elementos de la muestra.
Es importante para el fin que nos ocupa (aprender a crear objetos en R) que las variables pueden ser de dos tipos:
- Cuantitativas: cuando miden una cantidad y, en definitiva, los valores que observemos serán números propiamente dichos. En este caso, los objetos del vector serán de tipo numérico (num o numeric según la jerga de R). Esta clase puede dividirse en
- integrer cuando se trata de valores enteros, es decir, positivos y sin decimales o
- double en caso de que sean números reales.
- Cualitativas: cuando miden una cualidad y lo que observemos sea el valor de esa cualidad que, habitualmente, recogeremos en forma de palabras y, por tanto serán de tipo carácter (chr o character en R).
En cuanto a las variables cuantitivas, cabe hacer un pequeño inciso, importante de cara a la creación de vectores en R para variables cuantitativas.
Este tipo de variables puede recoger un valor diferente para cada individuo. Como los nombres de antes o como cuando te hacen una pregunta abierta en una encuesta. En ese caso, tener un vector con valores de tipo chr es más que suficiente. Sin embargo, la cosa cambia cuando la variable tiene unas categorías bien definidas como “sí” y “no”; “bueno”, “regular” y “malo”; o, en definitiva, como cuando en la encuesta de antes hay un desplegable del que debes elegir sólo una opción. En ese caso es importante recurrir a un tipo de vectores particulares a los que llamamos factores.
Los factores tienen la particularidad de que “saben” que todos los elementos que se corresponden con el mismo valor, son de la misma categoría y, para definirlos, usamos la función que lleva este mismo nombre factor
No voy a entrar hoy demasiado en explicar como se crea un factor ni sus particularidades porque es algo extenso y prefiero dejarlo para la siguiente entrada donde también hablaremos de algunos tipos especiales de datos como los valores lógicos, los NAs, las fechas… pero te dejo con la miel en los labios para la próxima.
Ahora toca seguir con más tipos de objetos pero no me puedo resistir a que hagas una prueba para que entiendas algo de los vectores que es importante. Vamos a añadirle al vector de edades un dato de tipo caracter.
Para añadir un nuevo valor a un vector basta con usar otra vez la función c y como argumentos poner el vector original, una coma y el valor nuevo que quiero añadir.
Vamos a ello pero antes fíjate muy bien en el environment. Todo esta como antes. En la edad pone num [1:5]. Ahora ejecuta:
> edad <- c(edad, "desconocida")
¿Qué ha pasado? Ha cambiado a chr ¿a qué sí?
Esto pasa porque los vectores son de tipo atómico y un objeto de este tipo sólo puede tener un tipo de datos. O son numéricos o caracter o es un factor… pero no los puedes mezclar.
Esto también les pasa a las matrices y a los arrays de los que ahora sí, vamos a empezar a hablar.
Arrays y matrices
Como he dejado caer al principio las matrices y los arrays pueden verse como un conjunto de valores que tienen una estructura de capas.
Para entender que significa esto pongamos un ejemplo. Imagina que has recogido la cantidad de lluvia media en 5 ciudades españolas durante los 12 meses del año.
Fíjate que si piensas en una ciudad, vas a tener 12 observaciones por lo que podrías pensar en un vector de 12 valores para esa ciudad, ¿cierto?
> yecla <- c(14.1, 16.5, 18.5, 23.9, 21.0, 15.6, 4.8, 7.3, 21.4, 30.8, 25.0, 18.5)
> valencia <- c(20.7, 21.9, 23.6, 27.9, 24.2, 13.2, 5.1, 11.7, 32.9, 43.7, 35.6, 26.2)
> ibiza <- c(36.8, 32.5, 29.9, 34.4, 26.2, 10.3, 5.4, 13.3, 39.2, 51.8, 57.4, 43.8)
> vigo <- c(131.0, 100.7, 86.3, 93.6, 72.3, 38.6, 19.8, 25.6, 64.6, 136.9, 144.2, 147.8)
> tenerife <- c(16.7, 14.4, 10.1, 5.2, 1.6, 0.5, 0.3, 1.5, 4.1, 9.2, 15.0, 19.0)
Por otro lado si piensas en un mes concreto, para ese mes tienes 5 valores (uno por ciudad). Podrías guardarlo de nuevo en un vector de 5 valores.
> enero <- c(14.1,20.7,36.8,131.0,16.7)
Esto nos indica que tenemos dos dimensiones o capas: la dimensión de la ciudad y la dimensión del tiempo. ¿Pero como lo guardamos todo junto? Pues en una matriz.
Los que estáis familiarizados con las matrices sabréis que son un tipo de estructura que tiene filas y columnas. En este caso las filas representarán las distintas ciudades y las columnas los distintos meses.
Para crear una matriz podemos hacerlo mediante diferentes funciones.
La función matrix
La función más utilizada es la función matrix. Esta parte de un vector al que dará la estructura deseada.
En nuestro ejemplo, yo podría hacer un único vector con todas las lluvias y después rellenar nuestra matriz indicándole que quiero 5 filas y 12 columnas. Sígueme:
> precip_vec <- c(yecla,valencia,ibiza,vigo,tenerife)
> precip_mat <- matrix(precip_vec, nrow=5, ncol=12)
veamos que ha guardado en precip_mat:
> precip_mat
## [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12]
## [1,] 14.1 15.6 25.0 27.9 32.9 32.5 5.4 43.8 72.3 136.9 10.1 1.5
## [2,] 16.5 4.8 18.5 24.2 43.7 29.9 13.3 131.0 38.6 144.2 5.2 4.1
## [3,] 18.5 7.3 20.7 13.2 35.6 34.4 39.2 100.7 19.8 147.8 1.6 9.2
## [4,] 23.9 21.4 21.9 5.1 26.2 26.2 51.8 86.3 25.6 16.7 0.5 15.0
## [5,] 21.0 30.8 23.6 11.7 36.8 10.3 57.4 93.6 64.6 14.4 0.3 19.0
¡Vaya! Si lo miráis con cuidado veréis que la primera columna no son exactamente las precipitaciones de enero para cada ciudad. Esto pasa porque la función matrix rellena la matriz por columnas así que tenemos que indicarle que lo queremos hacer por filas. Eso lo vamos a hacer activando un argumento de la función que se llama byrow. Así:
> precip_mat <- matrix(precip_vec, nrow = 5, ncol = 12, byrow = TRUE)
>
> precip_mat
## [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12]
## [1,] 14.1 16.5 18.5 23.9 21.0 15.6 4.8 7.3 21.4 30.8 25.0 18.5
## [2,] 20.7 21.9 23.6 27.9 24.2 13.2 5.1 11.7 32.9 43.7 35.6 26.2
## [3,] 36.8 32.5 29.9 34.4 26.2 10.3 5.4 13.3 39.2 51.8 57.4 43.8
## [4,] 131.0 100.7 86.3 93.6 72.3 38.6 19.8 25.6 64.6 136.9 144.2 147.8
## [5,] 16.7 14.4 10.1 5.2 1.6 0.5 0.3 1.5 4.1 9.2 15.0 19.0
Ahora sí, ya tenemos todos los datos en su sitio.
Pero la verdad es que podríamos haber aprovechado que ya teníamos los vectores de la filas (uno para cada ciudad). Para hacerlo podríamos haber tirado de las funciones rbind y cbind:
rbind y cbind
Estas funciones lo que hacen es unir por filas (rbind) o por columnas (cbind) los vectores que le digamos:
> precip_mat2 <- rbind(yecla,valencia,ibiza,vigo,tenerife)
> precip_mat2
## [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12]
## yecla 14.1 16.5 18.5 23.9 21.0 15.6 4.8 7.3 21.4 30.8 25.0 18.5
## valencia 20.7 21.9 23.6 27.9 24.2 13.2 5.1 11.7 32.9 43.7 35.6 26.2
## ibiza 36.8 32.5 29.9 34.4 26.2 10.3 5.4 13.3 39.2 51.8 57.4 43.8
## vigo 131.0 100.7 86.3 93.6 72.3 38.6 19.8 25.6 64.6 136.9 144.2 147.8
## tenerife 16.7 14.4 10.1 5.2 1.6 0.5 0.3 1.5 4.1 9.2 15.0 19.0
Fijate en algo curioso. Ahora la matriz tiene los nombres de las filas puestos, heredados del nombre de cada vector. Esto está muy bien porque puedes saber a que corresponde cada fila. Lo cierto es que podemos hacer lo mismo a mano para cada fila y cada columna usando las funciones rownames y colnames. Mira:
> rownames(precip_mat2)
## [1] "yecla" "valencia" "ibiza" "vigo" "tenerife"
> colnames(precip_mat2) <- c("ene", "feb", "mar", "abr", "may", "jun", "jul", "ago", "sep", "oct", "nov", "dic")
>
> precip_mat2
## ene feb mar abr may jun jul ago sep oct nov dic
## yecla 14.1 16.5 18.5 23.9 21.0 15.6 4.8 7.3 21.4 30.8 25.0 18.5
## valencia 20.7 21.9 23.6 27.9 24.2 13.2 5.1 11.7 32.9 43.7 35.6 26.2
## ibiza 36.8 32.5 29.9 34.4 26.2 10.3 5.4 13.3 39.2 51.8 57.4 43.8
## vigo 131.0 100.7 86.3 93.6 72.3 38.6 19.8 25.6 64.6 136.9 144.2 147.8
## tenerife 16.7 14.4 10.1 5.2 1.6 0.5 0.3 1.5 4.1 9.2 15.0 19.0
A estas caracteristicas añadidas a la matriz las llamamos atributos y van a ser muy importantes cuando estemos trabajando con datos.
Atributos
Algunos atributos importantes, además de los nombres, son la longitud de un vector o la dimensión de una matriz que básicamente nos dice el numero de posiciones en cada capa. Para saber que atributos tiene un objeto puedes usar, por ejemplo, la función length (para la longitud de un vector) la función dim (para las dimensiones de una matriz o un array) y str para observar la estructura general.
> str(precip_mat2)
## num [1:5, 1:12] 14.1 20.7 36.8 131 16.7 ...
## - attr(*, "dimnames")=List of 2
## ..$ : chr [1:5] "yecla" "valencia" "ibiza" "vigo" ...
## ..$ : chr [1:12] "ene" "feb" "mar" "abr" ...
> length(yecla)
## [1] 12
> dim(precip_mat2)
## [1] 5 12
Pero vamos a complicarlo un poco. Imagina que ahora añades las precipitaciones mensuales pero para cada año. Tenemos ahora una capa o dimensión más… ¿Cómo lo hacemos?
A las estructuras con más de dos dimensiones las llamamos en genérico arrays.
La función array
La función array es similar a la función matrix. Le pasamos un vector y le indicamos la dimensión, aunque esto ultimo ahora lo hacemos con el argumento dim al que le asignaremos un vector indicando cuantas posiciones quiero en cada capa o dimensión.
Para hacer esto vamos a crear un vector con los datos para, por ejemplo, de 4 años. Como realmente no los tengo, voy a aprovechar para enseñaros una función que tambien os puede ser util, la función rep. Esta función permite repetir un valor o un vector el número de veces que deseemos. Vamos a pensar entonces que las temperaturas mensuales se han repetido durante los últimos 4 años.
> precip_anual_vec <- rep(precip_vec, 4)
De esta forma puedes ver que tenemos 4 veces el mismo vector de 60 valores que teníamos en precip_vec. Podríamos haberlo hecho también repitiendo 4 veces cada valor. Para hacer eso sólo tienes que cambiar el 4 por el argumento each = 4.
La cuestión es que ya tenemos un vector que contiene la serie anual de cada ciudad para cada año. Es decir, tenemos que el orden de las capas en el vector es meses, ciudad, año. Teniendo esto en mente, la forma de conseguir nuestro array sería:
> precip_anual_array <- array(data = precip_anual_vec, dim = c(12,5,4))
> precip_anual_array
## , , 1
##
## [,1] [,2] [,3] [,4] [,5]
## [1,] 14.1 20.7 36.8 131.0 16.7
## [2,] 16.5 21.9 32.5 100.7 14.4
## [3,] 18.5 23.6 29.9 86.3 10.1
## [4,] 23.9 27.9 34.4 93.6 5.2
## [5,] 21.0 24.2 26.2 72.3 1.6
## [6,] 15.6 13.2 10.3 38.6 0.5
## [7,] 4.8 5.1 5.4 19.8 0.3
## [8,] 7.3 11.7 13.3 25.6 1.5
## [9,] 21.4 32.9 39.2 64.6 4.1
## [10,] 30.8 43.7 51.8 136.9 9.2
## [11,] 25.0 35.6 57.4 144.2 15.0
## [12,] 18.5 26.2 43.8 147.8 19.0
##
## , , 2
##
## [,1] [,2] [,3] [,4] [,5]
## [1,] 14.1 20.7 36.8 131.0 16.7
## [2,] 16.5 21.9 32.5 100.7 14.4
## [3,] 18.5 23.6 29.9 86.3 10.1
## [4,] 23.9 27.9 34.4 93.6 5.2
## [5,] 21.0 24.2 26.2 72.3 1.6
## [6,] 15.6 13.2 10.3 38.6 0.5
## [7,] 4.8 5.1 5.4 19.8 0.3
## [8,] 7.3 11.7 13.3 25.6 1.5
## [9,] 21.4 32.9 39.2 64.6 4.1
## [10,] 30.8 43.7 51.8 136.9 9.2
## [11,] 25.0 35.6 57.4 144.2 15.0
## [12,] 18.5 26.2 43.8 147.8 19.0
##
## , , 3
##
## [,1] [,2] [,3] [,4] [,5]
## [1,] 14.1 20.7 36.8 131.0 16.7
## [2,] 16.5 21.9 32.5 100.7 14.4
## [3,] 18.5 23.6 29.9 86.3 10.1
## [4,] 23.9 27.9 34.4 93.6 5.2
## [5,] 21.0 24.2 26.2 72.3 1.6
## [6,] 15.6 13.2 10.3 38.6 0.5
## [7,] 4.8 5.1 5.4 19.8 0.3
## [8,] 7.3 11.7 13.3 25.6 1.5
## [9,] 21.4 32.9 39.2 64.6 4.1
## [10,] 30.8 43.7 51.8 136.9 9.2
## [11,] 25.0 35.6 57.4 144.2 15.0
## [12,] 18.5 26.2 43.8 147.8 19.0
##
## , , 4
##
## [,1] [,2] [,3] [,4] [,5]
## [1,] 14.1 20.7 36.8 131.0 16.7
## [2,] 16.5 21.9 32.5 100.7 14.4
## [3,] 18.5 23.6 29.9 86.3 10.1
## [4,] 23.9 27.9 34.4 93.6 5.2
## [5,] 21.0 24.2 26.2 72.3 1.6
## [6,] 15.6 13.2 10.3 38.6 0.5
## [7,] 4.8 5.1 5.4 19.8 0.3
## [8,] 7.3 11.7 13.3 25.6 1.5
## [9,] 21.4 32.9 39.2 64.6 4.1
## [10,] 30.8 43.7 51.8 136.9 9.2
## [11,] 25.0 35.6 57.4 144.2 15.0
## [12,] 18.5 26.2 43.8 147.8 19.0
Fijate que ahora tienes 4 matrices de 12 filas y 5 columnas. Aquí hemos cambiado con respecto a las matrices anteriores porque hemos respetado el orden del vector que hemos utilizado, pero en realidad no es importante porque lo crucial es saber qué capa representa qué.
Y te preguntarás, vale y ¿no sería mejor tener los nombres de cada capa y posición para que fuera más evidente? Pues sí, tienes toda la razón. Eso lo vas a conseguir usando la función “dimnames”:
> dimnames(precip_anual_array) <- list(meses = c("ene", "feb", "mar", "abr", "may", "jun", "jul", "ago", "sep", "oct", "nov", "dic"), ciudades = c("yecla", "valencia", "ibiza", "vigo", "tenerife"), anualidad = c(2010, 2011, 2013, 2014))
>
> precip_anual_array
## , , anualidad = 2010
##
## ciudades
## meses yecla valencia ibiza vigo tenerife
## ene 14.1 20.7 36.8 131.0 16.7
## feb 16.5 21.9 32.5 100.7 14.4
## mar 18.5 23.6 29.9 86.3 10.1
## abr 23.9 27.9 34.4 93.6 5.2
## may 21.0 24.2 26.2 72.3 1.6
## jun 15.6 13.2 10.3 38.6 0.5
## jul 4.8 5.1 5.4 19.8 0.3
## ago 7.3 11.7 13.3 25.6 1.5
## sep 21.4 32.9 39.2 64.6 4.1
## oct 30.8 43.7 51.8 136.9 9.2
## nov 25.0 35.6 57.4 144.2 15.0
## dic 18.5 26.2 43.8 147.8 19.0
##
## , , anualidad = 2011
##
## ciudades
## meses yecla valencia ibiza vigo tenerife
## ene 14.1 20.7 36.8 131.0 16.7
## feb 16.5 21.9 32.5 100.7 14.4
## mar 18.5 23.6 29.9 86.3 10.1
## abr 23.9 27.9 34.4 93.6 5.2
## may 21.0 24.2 26.2 72.3 1.6
## jun 15.6 13.2 10.3 38.6 0.5
## jul 4.8 5.1 5.4 19.8 0.3
## ago 7.3 11.7 13.3 25.6 1.5
## sep 21.4 32.9 39.2 64.6 4.1
## oct 30.8 43.7 51.8 136.9 9.2
## nov 25.0 35.6 57.4 144.2 15.0
## dic 18.5 26.2 43.8 147.8 19.0
##
## , , anualidad = 2013
##
## ciudades
## meses yecla valencia ibiza vigo tenerife
## ene 14.1 20.7 36.8 131.0 16.7
## feb 16.5 21.9 32.5 100.7 14.4
## mar 18.5 23.6 29.9 86.3 10.1
## abr 23.9 27.9 34.4 93.6 5.2
## may 21.0 24.2 26.2 72.3 1.6
## jun 15.6 13.2 10.3 38.6 0.5
## jul 4.8 5.1 5.4 19.8 0.3
## ago 7.3 11.7 13.3 25.6 1.5
## sep 21.4 32.9 39.2 64.6 4.1
## oct 30.8 43.7 51.8 136.9 9.2
## nov 25.0 35.6 57.4 144.2 15.0
## dic 18.5 26.2 43.8 147.8 19.0
##
## , , anualidad = 2014
##
## ciudades
## meses yecla valencia ibiza vigo tenerife
## ene 14.1 20.7 36.8 131.0 16.7
## feb 16.5 21.9 32.5 100.7 14.4
## mar 18.5 23.6 29.9 86.3 10.1
## abr 23.9 27.9 34.4 93.6 5.2
## may 21.0 24.2 26.2 72.3 1.6
## jun 15.6 13.2 10.3 38.6 0.5
## jul 4.8 5.1 5.4 19.8 0.3
## ago 7.3 11.7 13.3 25.6 1.5
## sep 21.4 32.9 39.2 64.6 4.1
## oct 30.8 43.7 51.8 136.9 9.2
## nov 25.0 35.6 57.4 144.2 15.0
## dic 18.5 26.2 43.8 147.8 19.0
Uy… pero aquí hemos usado una función nueva, la función list. ¿Esto que es? Bueno, dejame que te cuente una cosa más de los arrays y pasamos a ellas.
Lo que quiero contarte es fácil. ¿Recuerdas que cuando estabamos hablando de vectores habiamos comentado que yo puedo ir y abrir la puertecita de una posición concreta para ver qué hay dentro? Pues con las matrices y los arrays pasa lo mismo sólo que ahora la puertecita necesita más de una indicación para que podamos llegar a ella. Por ejemplo, en los datos con estructura de matriz podemos querer acceder a la primera ciudad y el tercer mes, esto es, fila 1 columna 3. La forma de indicarlo será mediante corchetes y estos valores separados por una coma. Así:
> precip_mat2[1,3]
## [1] 18.5
Si quiero acceder a todos los datos de la primera ciudad, dejaré un espacio en blanco en lugar reservado a la columna. Así:
> precip_mat2[1,]
## ene feb mar abr may jun jul ago sep oct nov dic
## 14.1 16.5 18.5 23.9 21.0 15.6 4.8 7.3 21.4 30.8 25.0 18.5
Y si quiero acceder al mes de marzo en todas las ciudades, haré lo propio pero dejando en blanco ahora el primer valor:
> precip_mat2[,3]
## yecla valencia ibiza vigo tenerife
## 18.5 23.6 29.9 86.3 10.1
Si tenemos nombres puestos para cada posición también podemos aprovecharnos de ellos sustituyendo el número por el nombre:
> precip_mat2["yecla","mar"]
## [1] 18.5
Y una curiosidad más, si ponemos el valor con un simbolo menos delante, lo que haremos es decirle que nos de todo menos esa posición. Mira, así quitamos Yecla y el mes de marzo:
> precip_mat2[-1,-3]
## ene feb abr may jun jul ago sep oct nov dic
## valencia 20.7 21.9 27.9 24.2 13.2 5.1 11.7 32.9 43.7 35.6 26.2
## ibiza 36.8 32.5 34.4 26.2 10.3 5.4 13.3 39.2 51.8 57.4 43.8
## vigo 131.0 100.7 93.6 72.3 38.6 19.8 25.6 64.6 136.9 144.2 147.8
## tenerife 16.7 14.4 5.2 1.6 0.5 0.3 1.5 4.1 9.2 15.0 19.0
Y ahora sí vamos a por las listas y los data frames.
Listas y data frames. Cuando los datos no son atómicos.
Hasta ahora hemos visto formatos de datos atómicos, es decir, o todo eran números o todo eran caracteres. Pero que pasa cuando tengo que unir datos de más de una variable y estas son de diferente naturaleza.
Esto es un poco lo que nos ha pasado al querer poner los nombres a las dimensiones de nuestro array. Teniamos caracteres en 2 dimensiones, pero en los años teníamos números. Para esto usamos una lista.
Listas: el cajón desastre
Una lista es simplemente un cajón desastre donde cada elemento que ponemos dentro puede ser cualquier tipo de objeto de R de los que estamos viendo o de los que nos quedan por ver.
La forma de definir una lista, como ya hemos visto, es con la función list y podemos dar un nombre a cada elemento de la lista o simplmente ponerlos allí a montón (yo te recomiendo mejor lo primero).
> milista <- list(meses = c("ene", "feb", "mar", "abr", "may", "jun", "jul", "ago", "sep", "oct", "nov", "dic"), ciudades = c("yecla", "valencia", "ibiza", "vigo", "tenerife"), anualidad = c(2010, 2011, 2013, 2014))
Si ahora quiero recuperar alguno de sus elementos, vuelvo a recurrir al corchete pero con una particularidad, ahora pongo doble corchete:
> milista[[2]]
## [1] "yecla" "valencia" "ibiza" "vigo" "tenerife"
> milista[["anualidad"]]
## [1] 2010 2011 2013 2014
E incluso puedo acceder a una posición dentro de uno de los elementos:
> milista[[2]][3]
## [1] "ibiza"
Hablaremos más de listas y de como aprovechar su potencial pero, como ya he dicho, las listas son un poco cajón desastre y yo que soy muy ordenada, necesito otro tipo de estructura cuando tengo que guardar datos. Hablemos pues de data frames o bancos de datos.
Data frames, la estructura hecha para la estadística.
Cuando digo lo de cajón desastre me vengo a referir a que cada objeto de la lista puede ser cualquier cosa y no estar relacionados entre sí. Sin embargo, cuando se trata de guardar datos, habitualmente vamos a tener observaciones de varias variables para una misma muestra y queremos que estas observaciones estén ligadas entre sí. Dicho de otra forma, quieres saber que la primera observación de cada variable se corresponde con la primera muestra. Esto ya lo hacia el formato de matriz pero, claro, sólo podríamos tener variables numéricas.
La estructura perfecta que reune todas estas características es el data frame o banco de datos.
Se trata, básicamente, de una estructura como de matriz (de hecho puedes tratarla casi igual) pero donde las filas representan elementos de la muestra y las columnas diferentes variables. Así, cada columna tendrá un tipo de datos concretos pero cada columna puede ser distinta de las demás.
Si volvemos a nuestro ejemplo inicial donde teníamos datos de varias personas, podemos crear un data frame de la siguiente forma:
> nombre <- c("Ana", "Adriana", "Julio", "Clara", "Andrés")
> edad <- c(23, 24, 26, 21, 28)
> estatura <- c(1.67,1.60, 1.78, 1.70, 1.83)
> df <- data.frame(nombre, edad, estatura)
> df
## nombre edad estatura
## 1 Ana 23 1.67
## 2 Adriana 24 1.60
## 3 Julio 26 1.78
## 4 Clara 21 1.70
## 5 Andrés 28 1.83
Por supuesto, también podemos cargar bancos de datos que tengamos en otro formato como Excel o SPSS. Ya vimos como hacerlo en la entrada anterior. Si repites la lectura del banco de datos ambiente que ya hicimos allí verás como se te ha creado en forma de banco de datos (puedes verlo con la función str sobre el objeto resultante).
> library(haven)
> ambiente <- read_sav("ambiente.sav")
> str(ambiente)
## tibble [300 × 4] (S3: tbl_df/tbl/data.frame)
## $ SULFATO: num [1:300] 7.21 3.04 2.93 7.61 3.47 ...
## ..- attr(*, "format.spss")= chr "DOT8.4"
## ..- attr(*, "display_width")= int 11
## $ PH : num [1:300] 5.74 6.26 6.08 5.75 5.81 ...
## ..- attr(*, "format.spss")= chr "F8.4"
## $ OZONO : dbl+lbl [1:300] 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, ...
## ..@ format.spss: chr "F6.0"
## ..@ labels : Named num [1:2] 0 1
## .. ..- attr(*, "names")= chr [1:2] "Normal" "Alto"
## $ PROVIN : dbl+lbl [1:300] 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ...
## ..@ label : chr "Provincia"
## ..@ format.spss : chr "F5.0"
## ..@ display_width: int 13
## ..@ labels : Named num [1:3] 1 2 3
## .. ..- attr(*, "names")= chr [1:3] "ALICANTE" "CASTELLON" "VALENCIA"
Bueeeennooooo, vaaaaleeee,… pone tibble y no data.frame (que también). Déjame decir que este formato es una mejora de la estructura de data frame que ha hecho el equipo de R y que permite que los bancos de datos ocupen menos memoria. Pero como se usan exactamente igual… sigamos hablando de data frames.
La cuestión es que una vez tenemos nuestro banco de datos, podemos acceder a cada posición utilizando los corchetes como si de una matriz se tratase pero, además, podemos hacer uso de su estructura para seleccionar cada variable de un modo muy particular, con el símbolo $. Fijate:
> df$nombre
## [1] "Ana" "Adriana" "Julio" "Clara" "Andrés"
> df$edad
## [1] 23 24 26 21 28
Al poner el $ seguido del nombre de la variable, lo que tengo es un vector con los datos correspondientes únicamente a esa variable y puedo trabajar como si se tratase de eso exactamente, un vector:
> df$estatura[3]
## [1] 1.78
Seguiremos hablando mucho de bancos de datos, así que no me entretendré más por hoy porque vamos a ir terminando y antes quiero hacer unas reflexiones finales. Hablemos de coerción.
Forzando objetos y datos a ser lo que quieres que sean.
Esta nota final es sólo para mencionar que a veces tenemos datos en un formato que queremos cambiar. Puede que tengamos unos datos numéricos que queremos forzar a que sean de tipo caracter o viceversa. O puede que tengas una matriz que quieras poner en formato banco de datos.
Siempre que los formatos sean compatibles, podremos hacer esto con unas funciones especiales que llamamos de coerción y que empiezan siempre con “as.”. Por ejemplo, as.data.frame transformará un vector o una matriz en un banco de datos, as.numeric hará lo propio pasando lo que tenga dentro a numérico… aunque no siempre hace lo que tu crees que va a hacer, también te digo. Algunos otros ejemplos son:
Tipo | Coerción |
---|---|
array | as.array() |
character | as.character() |
complex | as.complex() |
double | as.double() |
integer | as.integer() |
list | as.list() |
matrix | as.matrix() |
Por supuesto, sólo me ha dado tiempo a darte una pincelada de los objetos en R, pero como vamos a seguir avanzando, iremos viendo muchas más cosas y aprenderemos a utilizarlos poco a poco, pero, de momento te invito a que juegues con lo que acabamos de ver y nos vemos dentro de dos semanas.
Espero que te haya gustado y te resulte útil ;-p
3 Replies to “Empezando en R (II). Objetos”