R: Old School vs tidyverse
Hace algunos años este pibe de moñito vino a sacarnos de la modorra y cambiar la forma de programar en R.
Hadley Wickham
Hadley creó un ecosistema de paquetes, conocido como tidyverse, que permite manipular, explorar y visualizar datos.
Estas cosas ya se podían hacer en R base, entonces ¿qué aportó el tidyverse? principalmente coherencia, algo en lo que R estaba escaso. Trabajar en un equipo pequeño permitió asegurar que todos los paquetes respetan la misma lógica y filosofía. Además se simplificaron algunas tareas básicas, poniendo énfasis en que sea más fácil de aprender y más productivo, requiriendo menos tiempo de programación.
No todo es color de rosa, el tidyverse tiene sus limitaciones. En especial cuando trabajamos con datos que no tienen formato de tabla. Por esta razón siempre van a convivir los dos sistema y está en cada analista de datos decidir cual es la mejor alternativa para su problema particular.
Hoy vamos a comparar como se realiza la misma tarea en R base (Old School) y tidyverse, usando nuevamente el dataset starwars.
> library(tidyverse)
Selección de filas
Una de las operaciones que hacemos más a menudo cuando analizamos datos es seleccionar filas (usualmente, filas = observaciones). En este caso queremos trabajar solo con los personajes humanos de Star Wars. ¿Cómo hacemos eso en R base y en el tidyverse?
Old School
Lo vamos a hacer utilizando el operador de selección [ ] junto con el operador de comparación ==
> humans <- starwars[starwars$species == "Human",]
tidyverse
Debemos utilizar la función filter junto con el operador de comparación ==.
> humant <- filter(starwars, species == "Human")
El resultado es:
A tibble: 35 x 13
name height mass hair_color skin_color eye_color birth_year gender
<chr> <int> <dbl> <chr> <chr> <chr> <dbl> <chr>
1 Luke Skywal~ 172 77 blond fair blue 19 male
2 Darth Vader 202 136 none white yellow 41.9 male
3 Leia Organa 150 49 brown light brown 19 female
4 Owen Lars 178 120 brown, grey light blue 52 male
5 Beru Whites~ 165 75 brown light blue 47 female
6 Biggs Darkl~ 183 84 black light brown 24 male
7 Obi-Wan Ken~ 182 77 auburn, wh~ fair blue-gray 57 male
8 Anakin Skyw~ 188 84 blond fair blue 41.9 male
9 Wilhuff Tar~ 180 NA auburn, gr~ fair blue 64 male
10 Han Solo 180 80 brown fair brown 29 male
... with 25 more rows, and 5 more variables: homeworld <chr>, species <chr>,
films <list>, vehicles <list>, starships <list>
También podemos querer filtrar por dos criterios al mismo tiempo. En este caso buscamos a aquellos humanos que midan más de 1.85.
Old School
Similar al caso anterior pero ahora tenemos dos condiciones, que relacionaremos mediante el operador &.
> altos.s <- starwars[starwars$species == "Human" &
starwars$height > 185,]
tidyverse
En el caso de filter, podemos agregar más condiciones simplemente separándolas con comas.
> altos.t <- filter(starwars, species == "Human",
starwars$height > 185)
El resultados en ambos casos es:
name height mass hair_color skin_color eye_color birth_year gender
<chr> <int> <dbl> <chr> <chr> <chr> <dbl> <chr>
1 Darth Vader 202 136 none white yellow 41.9 male
2 Anakin Skywal~ 188 84 blond fair blue 41.9 male
3 Qui-Gon Jinn 193 89 brown fair blue 92 male
4 Mace Windu 188 84 none dark brown 72 male
5 Dooku 193 80 white fair brown 102 male
6 Bail Prestor ~ 191 NA black tan brown 67 male
7 Raymus Antill~ 188 79 brown light brown NA male
... with 5 more variables: homeworld <chr>, species <chr>, films <list>,
vehicles <list>, starships <list>
Reordenar filas
El siguiente paso es ordenar los personajes según su altura y su peso.
Old School
Usamos la función order en conjunto con el operador de selección [ ].
> altos.s[order(altos.s$height, altos.s$mass),]
tidyverse
Usamos la función arrange
> arrange(altos.t, height, mass)
El resultado es:
A tibble: 7 x 13
name height mass hair_color skin_color eye_color birth_year gender
<chr> <int> <dbl> <chr> <chr> <chr> <dbl> <chr>
1 Raymus Antill~ 188 79 brown light brown NA male
2 Anakin Skywal~ 188 84 blond fair blue 41.9 male
3 Mace Windu 188 84 none dark brown 72 male
4 Bail Prestor ~ 191 NA black tan brown 67 male
5 Dooku 193 80 white fair brown 102 male
6 Qui-Gon Jinn 193 89 brown fair blue 92 male
7 Darth Vader 202 136 none white yellow 41.9 male
... with 5 more variables: homeworld <chr>, species <chr>, films <list>,
vehicles <list>, starships <list>
Seleccion de columnas
A veces tenemos muchas variables y queremos crear un nuevo dataset con una selección de las que más nos interesan. Tanto en R base como en el tidyverse hay más de una manera de hacer esto.
Old School
Forma 1: usando los nombres de columna
> altos.s[,c("name", "height", "mass", "hair_color")]
Forma 2: usando indices
> altos.s[,1:4]
tidyverse
Forma 1: nombrando explicitamente las columnas
> select(starwars, name, height, mass, hair_color)
Forma 2: nombrando solo la primera y la última
> select(starwars, name:hair_color)
El resultados en todos los casos es:
name height mass hair_color
<chr> <int> <dbl> <chr>
1 Luke Skywalker 172 77 blond
2 C-3PO 167 75 NA
3 R2-D2 96 32 NA
4 Darth Vader 202 136 none
5 Leia Organa 150 49 brown
6 Owen Lars 178 120 brown, grey
7 Beru Whitesun lars 165 75 brown
8 R5-D4 97 32 NA
9 Biggs Darklighter 183 84 black
10 Obi-Wan Kenobi 182 77 auburn, white
# ... with 77 more rows
Algo interesante de select es que tiene un montón de funciones auxiliares piolas como:
- starts_with(“abc”), busca nombres de columna que empiecen con “abc”.
- ends_with(“xyz”), busca nombres de columna que terminen con “xyz”.
- contains(“ijk”), busca nombres de columna que contengan la cadena “ijk”.
- matches(“(.)\1”), selecciona columnas en base a expresiones regulares
- num_range(“x”, 1:3), selecciona x1, x2 y x3.
Agregar columnas
Queremos crear una nueva columna, llamada bmi, con el índice de masa corporal de cada personaje. El bmi se calcula como peso / altura^2.
Old School
El operador $ permite acceder al contenido de una columna. En este caso, como estamos accediendo a una columna que aún no existe (bmi), de hecho la estamos creando.
> altos.s$bmi <- altos.s$mass / (altos.s$height/100)^2
tidyverse
La función mutate permite crear nuevas variables que sean transformaciones de otras.
> altos.t <- mutate(altos.t,
bmi = mass / (height/100)^2)
El resultado es:
name height mass bmi
<chr> <int> <dbl> <dbl>
1 Darth Vader 202 136 33.3
2 Anakin Skywalker 188 84 23.8
3 Qui-Gon Jinn 193 89 23.9
4 Mace Windu 188 84 23.8
5 Dooku 193 80 21.5
6 Bail Prestor Organa 191 NA NA
7 Raymus Antilles 188 79 22.4
Combinando operaciones
Una de las características más relevantes del tidyverse es que permite combinar operaciones usando el pipe (%>%). De esta manera nos ahorramos el paso de crear objetos con resultados intermedios.
> altos.t <- starwars %>%
filter(species == "Human", starwars$height > 185) %>%
select(name:hair_color) %>%
mutate(bmi = mass / (height/100)^2)
> altos.t
A tibble: 7 x 5
name height mass hair_color bmi
<chr> <int> <dbl> <chr> <dbl>
1 Darth Vader 202 136 none 33.3
2 Anakin Skywalker 188 84 blond 23.8
3 Qui-Gon Jinn 193 89 brown 23.9
4 Mace Windu 188 84 none 23.8
5 Dooku 193 80 white 21.5
6 Bail Prestor Organa 191 NA black NA
7 Raymus Antilles 188 79 brown 22.4
¿Y ustedes que usan en el día a día? ¿#teamBaseR o #teamTidyverse?
Nos vemos la próxima y si les gustó el post recuerden comentar / compartir / megustear.
Desde aquí pueden descargar el script completo para R.
Leave a comment