[RDS] Ejercicios resueltos para la sección 3.3.1

Continuamos con la serie de ejercicios resueltos para el weblibro “R for Data Science“, al que podéis acceder desde este enlace. En esta ocasión nos ocuparemos de la sección 3.3.1, correspondiente a los problemas que tratan de asentar el manejo de los elementos estéticos a la hora de generar gráficos con la función ggplot().

# 1. What’s gone wrong with this code?
#    Why are the points not blue?

library(tidyverse)
ggplot(data = mpg) +
    geom_point(mapping = aes(x = displ, y = hwy, color = "blue"))

Si ejecutamos el anterior bloque de instrucciones, esta es la imagen que aparece en pantalla:

ej-3-3-1-1-1

El argumento color = "blue" no debe colocarse dentro de la función aes() si pretendemos que afecte a todos los puntos, sino fuera de ella. En su interior lo podemos utilizar si, por ejemplo, deseamos que el color de los puntos se establezca dependiendo del valor que tome cierta variable (y en lugar de emplear “blue”, escribiríamos el respectivo nombre de dicha variable).

Así pues, para solucionar el problema simplemente tendríamos que escribir:

ggplot(data = mpg) +
    geom_point(mapping = aes(x = displ, y = hwy), color = "blue")

ej-3-3-1-1-2

# 2. Which variables in mpg are categorical?
#    Which variables are continuous?
#    (Hint: type ?mpg to read the documentation for the dataset).
#    How can you see this information when you run mpg?

?mpg

Si accedemos a la documentación asociada a este conjunto de datos, en la sección Format podemos encontrar esta breve descripción del conjunto de variables que incluye:

A data frame with 234 rows and 11 variables

- manufacturer.
- model.
- displ. engine displacement, in litres
- year.
- cyl. number of cylinders
- trans. type of transmission
- drv. f = front-wheel drive, r = rear wheel drive, 4 = 4wd
- cty. city miles per gallon
- hwy. highway miles per gallon
- fl.
- class.

Nadie puede poner en duda que la información proporcionada es ciertamente escasa. Por el nombre de las variables, a primera vista, podemos sospechar que manufacturer, model, trans, drv y class serán categóricas, de tipo nominal (para más información sobre la clasificación de variables en estadística, puede resultarnos de ayuda este artículo).

El resto de variables (salvo fl, que, al menos para mí, es un misterio) tiene sentido clasificarlas como continuas, de tipo ratio. No obstante, para asegurarnos, si tecleamos mpg obtendremos un poco más de información en la consola:

# A tibble: 234 × 11
   manufacturer      model displ  year   cyl      trans   drv   cty   hwy
          <chr>      <chr> <dbl> <int> <int>      <chr> <chr> <int> <int>
1          audi         a4   1.8  1999     4   auto(l5)     f    18    29
2          audi         a4   1.8  1999     4 manual(m5)     f    21    29
3          audi         a4   2.0  2008     4 manual(m6)     f    20    31
4          audi         a4   2.0  2008     4   auto(av)     f    21    30
5          audi         a4   2.8  1999     6   auto(l5)     f    16    26
6          audi         a4   2.8  1999     6 manual(m5)     f    18    26
7          audi         a4   3.1  2008     6   auto(av)     f    18    27
8          audi a4 quattro   1.8  1999     4 manual(m5)     4    18    26
9          audi a4 quattro   1.8  1999     4   auto(l5)     4    16    25
10         audi a4 quattro   2.0  2008     4 manual(m6)     4    20    28
# ... with 224 more rows, and 2 more variables: fl <chr>, class <chr>

Debajo de cada variable nos indican que tipo de dato que han utilizado para almacenarla. Así, las variables que antes indicamos eran categóricas, de tipo nominal, vienen codificadas en la clase chr y sus valores son cadenas de texto. Por otro lado, las que dijimos eran continuas, de tipo ratio, están codificadas bien como int, bien como dbl, en función de si los valores que se registren son números enteros o decimales.

Podemos dar otra vuelta de tuerca más a esta cuestión utilizando la función unique(), que nos muestra los distintos valores que una variable toma, lo cual es de suma utilidad a la hora de llevar a cabo su clasificación. Así:

unique(mpg$manufacturer) # nominal
# [1] "audi"       "chevrolet"  "dodge"      "ford"       "honda"
# [6] "hyundai"    "jeep"       "land rover" "lincoln"    "mercury"
# [11] "nissan"     "pontiac"    "subaru"     "toyota"     "volkswagen"

unique(mpg$model) # nominal
# [1] "a4"                     "a4 quattro"             "a6 quattro"
# [4] "c1500 suburban 2wd"     "corvette"               "k1500 tahoe 4wd"
# [7] "malibu"                 "caravan 2wd"            "dakota pickup 4wd"
# [10] "durango 4wd"            "ram 1500 pickup 4wd"    "expedition 2wd"
# [13] "explorer 4wd"           "f150 pickup 4wd"        "mustang"
# [16] "civic"                  "sonata"                 "tiburon"
# [19] "grand cherokee 4wd"     "range rover"            "navigator 2wd"
# [22] "mountaineer 4wd"        "altima"                 "maxima"
# [25] "pathfinder 4wd"         "grand prix"             "forester awd"
# [28] "impreza awd"            "4runner 4wd"            "camry"
# [31] "camry solara"           "corolla"                "land cruiser wagon 4wd"
# [34] "toyota tacoma 4wd"      "gti"                    "jetta"
# [37] "new beetle"             "passat"     

unique(mpg$displ) # continua
# [1] 1.8 2.0 2.8 3.1 4.2 5.3 5.7 6.0 6.2 7.0 6.5 2.4 3.5 3.6 3.0 3.3 3.8 4.0
# [19] 3.7 3.9 4.7 5.2 5.9 4.6 5.4 5.0 1.6 2.5 2.7 6.1 4.4 5.6 2.2 3.4 1.9

unique(mpg$year) # continua
# [1] 1999 2008

unique(mpg$cyl) # continua
# [1] 4 6 8 5

unique(mpg$trans) # nominal
# [1] "auto(l5)"   "manual(m5)" "manual(m6)" "auto(av)"   "auto(s6)"
# [6] "auto(l4)"   "auto(l3)"   "auto(l6)"   "auto(s5)"   "auto(s4)"

unique(mpg$drv) # nominal
# [1] "f" "4" "r"

unique(mpg$cty) # continua
# [1] 18 21 20 16 19 15 17 14 11 13 12 22  9 28 24 25 23 26 33 35 29

unique(mpg$hwy) # continua
# [1] 29 31 30 26 27 25 28 24 23 20 15 17 19 14 22 21 18 12 16 33 32 34 36 35 37
# [26] 44 41

unique(mpg$fl) # nominal
# [1] "p" "r" "e" "d" "c"

unique(mpg$class) # nominal
# [1] "compact"    "midsize"    "suv"        "2seater"    "minivan"
# [6] "pickup"     "subcompact"

De todas formas, este tipo de clasificaciones siempre hemos de considerarlo con cautela. Dependerá del investigador y de los objetivos del estudio el tipo final de cualquier variable considerada en el conjunto de datos. Es más que habitual, por ejemplo, que variables continuas acaben dicotomizadas.

# 3. Map a continuous variable to color, size, and shape.
#    How do these aesthetics
#    behave differently for categorical vs. continuous variables?

ggplot(data = mpg) +
    geom_point(mapping = aes(x = displ, y = hwy, color = cty))

ej-3-3-1-3-1

En lugar de asignar un color distinto a cada uno de los diferentes puntos, lo cual sería una auténtica locura visual, se genera un gradiente del mismo color en función del valor de la variable cty y cada punto recibe la tonalidad correspondiente.

ggplot(data = mpg) +
    geom_point(mapping = aes(x = displ, y = hwy, size = cty))

ej-3-3-1-3-2

Por lo que al tamaño respecta, se agrupan los valores de la variable continua en un número razonable de categorías, y a cada una de ellas se le asigna un tamaño que aumenta a medida que se incrementa el valor de la mencionada variable. Después, a cada punto del gráfico se le asigna el tamaño de la categoría cuyo representante posee un valor numérico más cercano al mismo.

ggplot(data = mpg) +
    geom_point(mapping = aes(x = displ, y = hwy, alpha = cty))

ej-3-3-1-3-3

El parámetro que controla la transparencia de los puntos presenta un comportamiento ciertamente similar al del tamaño, por lo que todo lo comentado en el párrafo anterior conserva su validez aquí.

ggplot(data = mpg) +
    geom_point(mapping = aes(x = displ, y = hwy, shape = cty))
# Error: A continuous variable can not be mapped to shape

Al intentar utilizar una variable continua para el parámetro que especifica la forma de los puntos del diagrama, la consola nos devuelve un error, indicándonos que es imposible llevar a cabo esta acción.

En un primer momento, pensé que el error podía deberse a la gran cantidad de valores que toma la variable cty. No obstante, es un mensaje difícil de esquivar de manera directa, ya que incluso aparece cuando intentamos que la forma de los puntos dependa de los cuatro valores que presenta la variable cyl.

En este último caso, podemos sortear el escollo convirtiendo la variable en categórica a partir de la función factor(), de forma que:

ggplot(data = mpg) +
    geom_point(mapping = aes(x = displ, y = hwy, shape = factor(cyl)))

ej-3-3-1-3-4

No obstante, el recurso arroja un resultado tremendamente horroroso si lo utilizamos con la variable original que hemos propuesto a lo largo de la resolución de este ejercicio:

ggplot(data = mpg) +
    geom_point(mapping = aes(x = displ, y = hwy, shape = factor(cty)))
# Warning messages:
# 1: The shape palette can deal with a maximum of 6 discrete values because
# more than 6 becomes difficult to discriminate; you have 21. Consider
# specifying shapes manually if you must have them.
# 2: Removed 137 rows containing missing values (geom_point).
# 3: The shape palette can deal with a maximum of 6 discrete values because
# more than 6 becomes difficult to discriminate; you have 21. Consider
# specifying shapes manually if you must have them.

ej-3-3-1-3-5

# 4. What happens if you map the same variable
#    to multiple aesthetics?

ggplot(data = mpg) +
    geom_point(mapping = aes(x = displ, y = hwy, color = class, size = class))

ej-3-3-1-4-1

Podemos apreciar como se genera una combinación de ambas estéticas. Al igual que antes, tenemos que ser cautos a la hora de asignar variables continuas a ciertos parámetros, puesto que los problemas que aparecieron en el ejercicio anterior aquí van a continuar presentándose.

ggplot(data = mpg) +
    geom_point(mapping = aes(x = displ, y = hwy, color = class, shape = class))
# Warning messages:
# 1: The shape palette can deal with a maximum of 6 discrete values because
# more than 6 becomes difficult to discriminate; you have 7. Consider
# specifying shapes manually if you must have them.
# 2: Removed 62 rows containing missing values (geom_point).
# 3: The shape palette can deal with a maximum of 6 discrete values because
# more than 6 becomes difficult to discriminate; you have 7. Consider
# specifying shapes manually if you must have them.

ej-3-3-1-4-2

Dejo un ejemplo adicional a continuación:

ggplot(data = mpg) +
    geom_point(mapping = aes(x = displ, y = hwy, color = class, alpha = class))

ej-3-3-1-4-3

# 5. What does the stroke aesthetic do?
#    What shapes does it work with?
#    (Hint: use ?geom_point)

?geom_point

Si accedemos a la documentación de la función indicada y descendemos hasta la sección de ejemplos, podremos encontrar la siguiente afirmación:

Use the stroke aesthetic to modify the width of the border

Tiempo de que experimentemos un poco con los valores para este parámetro, para hacernos una idea así de su funcionamiento:

ggplot(data = mpg) +
    geom_point(mapping = aes(x = displ, y = hwy, stroke = 1), shape = 1)

ej-3-3-1-5-1

ggplot(data = mpg) +
    geom_point(mapping = aes(x = displ, y = hwy, stroke = 2), shape = 1)

ej-3-3-1-5-2

ggplot(data = mpg) +
    geom_point(mapping = aes(x = displ, y = hwy, stroke = 5), shape = 1)

ej-3-3-1-5-3

A primera vista, tal y como hemos generado estos ejemplos, más que el borde del punto, parece que estemos simplemente cambiando su tamaño. Quizá el efecto quede más resaltado si utilizamos una forma para los puntos con un color de borde distinto al de su interior.

ggplot(data = mpg) +
    geom_point(mapping = aes(x = displ, y = hwy, stroke = 1), shape = 1)

ej-3-3-1-5-4

ggplot(data = mpg) +
    geom_point(mapping = aes(x = displ, y = hwy, stroke = 2), shape = 1)

ej-3-3-1-5-5

ggplot(data = mpg) +
    geom_point(mapping = aes(x = displ, y = hwy, stroke = 5), shape = 1)

ej-3-3-1-5-6

Efectivamente, así queda más claro que estamos controlando el tamaño del borde del punto.

# 6. What happens if you map an aesthetic to something
#    other than a variable name, like aes(colour = displ < 5)?

ggplot(data = mpg) +
    geom_point(mapping = aes(x = displ, y = hwy, color = displ < 5))

ej-3-3-1-6

En la imagen anterior podemos observar como se asigna un valor u otro de la estética seleccionada en función de si el punto verifica o no la condición lógica escogida. Este recurso lo encuentro sumamente interesante, aunque, para mi gusto, opino que tendríamos que invertir un poco de tiempo configurando el aspecto de la leyenda. En lugar de mostrar FALSE y TRUE, preferiría que se mostrase la propia condición lógica ahí.

Extra: apoyándonos en este tutorial, podemos conseguir lo propuesto en el párrafo anterior (sí, soy de esas personas a las que les viene una idea a la cabeza y no paran hasta que descubren cómo se puede llevar a cabo).

ggplot(data = mpg) +
    geom_point(mapping = aes(x = displ, y = hwy, color = displ < 5)) +
    guides(color = guide_legend(title = NULL)) +
    scale_color_discrete(labels = c("displ >= 5", "displ < 5"))

ej-3-3-1-6-2

Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s