📝 Ejercicios recopilados

Aquí haremos una recopilación de los ejercicios planteados a lo largo del curso. Vuelve por aquí si quieres cuando acabas las lecciones para repasar aquellos ejercicios que más te hayan costado.

Primeros pasos

(haz click en las flechas para ver soluciones)

📝Ejercicio 1: en tu consola (parte inferior de tu pantalla), asigna los valores 2 y 5 a dos variables a y b. Tras asignarles valores, multiplica los números en consola (haz click en la flecha para la solución propuesta).

  • Solución:
# Para poner comentarios en el código se usa #

# Definición de variables
a <- 2
b <- 5

# Multiplicación
a * b
## [1] 10
Multiplicación de a y b.

Imagen/gráfica 0.1: Multiplicación de a y b.

 

📝Ejercicio 2: modifica el código inferior para definir dos variables c y d, con valores 3 y -1, y calcular la división c/d (haz click en la flecha para la solución propuesta).

# Definición de variables
c <- 
d <-

# Operación (división)
c ? d

  • Solución:
# Definición de variables
c <- 3
d <- -1

# División
a / b
## [1] 0.4

 

📝Ejercicio 3: repite el ejercicio 1 pero ahora guarda el resultado de la multiplicación final en una variable c. Para ver el resultado guardado en c escribe dicha variable en consola (haz click en la flecha para la solución propuesta).

  • Solución:
# Variables
a <- 2
b <- 5

# Resultado
c <- a * b

# Muestro en consola
c
## [1] 10
Multiplicación de a y b guardando el resultado.

Imagen/gráfica 0.2: Multiplicación de a y b guardando el resultado.

 

📝Ejercicio 4: asigna ahora los valores 1, -2, 3 a tres variables a, b y c, y calcula la raíz cuadrada de cada uno.

  • Solución:
# Variables
a <- 1
b <- -2
c <- 3

# Resultado
sqrt(a)
## [1] 1
sqrt(b)
## [1] NaN
sqrt(c)
## [1] 1.732051

 

📝Ejercicio 5: repite el ejercicio 3 pero ahora escribe el código en un script (fichero de .R, guardado en script01.R). Recuerda al acabar seleccionar las líneas a ejecutar y clickar Run, o bien guardar el script con Source on save activado (haz click en la flecha para la solución propuesta).

  • Solución:
Multiplicación de a y b guardando el resultado pero escribiendo en el script.

Imagen/gráfica 0.3: Multiplicación de a y b guardando el resultado pero escribiendo en el script.

 

📝Ejercicio 6: calcula en consola la suma de 3 más 4, y todo ello multiplicado por 10, y asígnalo a una variable x (haz click en la flecha para la solución propuesta).

  • Solución:
x <- (3 + 4) * 10

 

📝Ejercicio 7: asigna un valor positivo a x y calcula su raíz cuadrada; asigna otro negativo y calcula su valor absoluto (haz click en la flecha para la solución propuesta).

  • Solución:
# Raíz cuadrada
x <- 73
sqrt(x)
## [1] 8.544004
# Valor absoluto
y <- -73
abs(y)
## [1] 73

 

CONSEJO:

Las órdenes sqrt(x) y abs(y) se llaman funciones, y la variable que tienen entre paréntesis se llama argumento de la función: una variable que toma de entrada la función y con la que opera internamente.

 

📝Ejercicio 8: usando la variable x ya definida, calcula la resta x - 5 y guárdala en una nueva variable z (haz click en la flecha para la solución propuesta).

  • Solución:
z <- x - 5
z
## [1] 68

 

📝Ejercicio 9: usando las variables x y z ya definidas, calcula el máximo de ambas, y guárdalo en una nueva variable t. (haz click en la flecha para la solución propuesta).

  • Solución:
t <- max(x, z)
t
## [1] 73

 

WARNING:

No hace falta gastar una línea por cada orden que quieras ejecutar. Tampoco necesitas guardar cada paso intermedio que realices. Cuidado con la memoria: cada asignación que hagas es una variable guardada que consume recursos en tu ordenador.

Tipos de datos

Scripts usados:

(haz click en las flechas para ver soluciones)

📝Ejercicio 1: define una variable que guarde tu edad, otra con tu nombre, otra respondiendo a la pregunta «¿tengo hermanos?» y otra con la fecha de tu nacimiento.

  • Solución:
edad <- 32 # tipo numeric
nombre <- "Javier" # tipo caracter
hermanos <- TRUE # tipo hermanos
fecha_nacimiento <- as.Date("1989-09-10") # tipo fecha

 

📝Ejercicio 2: define otra variable con tus apellidos y junta las variables nombre y apellidos en una sola variable nombre_completo.

  • Solución:
library(glue)

# Apellidos
apellidos <- "Álvarez Liébana"

# Pegamos
nombre_completo <- glue("{nombre} {apellidos}")
nombre_completo
## Javier Álvarez Liébana
# Otra forma
nombre_completo <- paste(nombre, apellidos)
nombre_completo
## [1] "Javier Álvarez Liébana"

 

📝Ejercicio 3: construye una frase que diga «Hola, me llamo … y tengo … años. Nací el … de … de …» (con el nombre completo).

  • Solución:
library(lubridate)
dia_nacimiento <- day(fecha_nacimiento)
mes_nacimiento <- month(fecha_nacimiento)
a_nacimiento <- year(fecha_nacimiento)

glue("Hola, me llamo {nombre_completo} y tengo {edad} años. Nací el {dia_nacimiento} del {mes_nacimiento} de {a_nacimiento}")
## Hola, me llamo Javier Álvarez Liébana y tengo 32 años. Nací el 10 del 9 de 1989

 

📝Ejercicio 4: calcula los días que han pasado desde la fecha de tu nacimiento

  • Solución:
days(today() - fecha_nacimiento)
## [1] "11830d 0H 0M 0S"

 

📝Ejercicio 5: obtén una variable lógica que nos diga si se cumplen (todas) las condiciones i) menor de 30 años (edad < 30); ii) con hermanos (hermanos == TRUE); iii) nacido en 1990 o posterior (fecha_nacimiento >= as.Date("1990-01-01")).

  • Solución:
# Se tienen que cumplir todas
edad < 30 & fecha_nacimiento >= as.Date("1990-01-01") & hermanos
## [1] FALSE
# otra forma
edad < 30 & fecha_nacimiento >= as.Date("1990-01-01") & hermanos == TRUE
## [1] FALSE

 

📝Ejercicio 6: modifica el código del ejercicio anterior para obtener una variable lógica que nos diga si se cumplen (al menos) alguna de las condiciones i) menor de 30 años; ii) con hermanos; iii) nacido en 1990 o posterior. Al contrario que antes, no necesitamos que se cumplan todas, nos basta con que se cumple al menos una.

  • Solución:
# Se tienen que cumplir todas
edad < 30 | fecha_nacimiento >= as.Date("1990-01-01") | hermanos
## [1] TRUE

 

📝Ejercicio 7: calcula la fecha 11 días más tarde a tu fecha de nacimiento. Obtén la semana del año de dicha fecha y el día de la semana con las funciones week, wday y weekdays.

  • Solución:
# Podemos sumar porque es fecha
fecha_post <- fecha_nacimiento + 11
fecha_post
## [1] "1989-09-21"
# Semana del año
week(fecha_post)
## [1] 38
# Día de la semana (versión americana, empiezan el domingo)
wday(fecha_post)
## [1] 5
# Día de la semana (versión española)
wday(fecha_post, week_start = 1)
## [1] 4
# Día de la semana en texto
weekdays(fecha_post)
## [1] "Thursday"

 

📝Ejercicio 8: define dos números cualesquiera en variable a y b. Calcula su suma y determina cual es mayor.

  • Solución:
a <- -5
b <- 7

# Suma
c <- a + b
c
## [1] 2
# Comparaciones
a == b # ¿a = b?
## [1] FALSE
a < b # ¿a < b?
## [1] TRUE

 

Vectores

(haz click en las flechas para ver soluciones)

📝Ejercicio 1: modifica el código anterior para crear un vector de nombre vector_num que contenga los números 1, 5 y -7.

# Vector de números
vector_num <- c(1)
vector_num

  • Solución:
# Vector de números
vector_num <- c(1, 5, -7)
vector_num
## [1]  1  5 -7

 

📝Ejercicio 2: define un vector que contenga los números 1, 10, -1 y 2, y guárdalo en una variable llamada vector_num.

  • Solución:
# Vector de números
vector_num <- c(1, 10, -1, 2)
vector_num
## [1]  1 10 -1  2

 

📝Ejercicio 3: obtén la longitud del vector anterior vector_num.

  • Solución:
# Longitud del vector
length(vector_num)
## [1] 4

 

📝Ejercicio 4: crea un vector con las palabras “Hola”, “me”, “llamo” (y tu nombre y apellidos), y pega luego sus elementos de forma que la frase esté correctamente escrita en castellano. Tras hacerlo, añade “y tengo 30 años”.

  • Solución:
# Definiendo el vector
vector_char <- c("Hola", "me", "llamo", "Javier",
                 "Álvarez", "Liébana")

# Pegamos
frase <- paste(vector_char, collapse = " ")
frase
## [1] "Hola me llamo Javier Álvarez Liébana"
# Añadimos frase
glue("{frase} y tengo 30 años.")
## Hola me llamo Javier Álvarez Liébana y tengo 30 años.
# Otra forma
paste0(frase, " y tengo 30 años.")
## [1] "Hola me llamo Javier Álvarez Liébana y tengo 30 años."
# Otra forma
paste(frase, "y tengo 30 años.")
## [1] "Hola me llamo Javier Álvarez Liébana y tengo 30 años."

 

📝Ejercicio 5: el código inferior crea una secuencia de números, que empieza en -1, que acaba en 32, y que va saltando de 2 en 2. Modíficalo para que haga el salto de 3 en 3 y guárdalo en una variable llamada secuencia.

seq(-1, 32, by = 2)

  • Solución:
secuencia <- seq(-1, 32, by = 3)
secuencia
##  [1] -1  2  5  8 11 14 17 20 23 26 29 32
length(secuencia) # longitud de la secuencia
## [1] 12

 

📝Ejercicio 6: crea una secuencia de números, que empiece en -1, que acabe en 32, y que tenga longitud 12.

  • Solución:
secuencia <- seq(-1, 32, l = 12)
secuencia
##  [1] -1  2  5  8 11 14 17 20 23 26 29 32
length(secuencia) # longitud de la secuencia
## [1] 12

 

📝Ejercicio 7: crea una secuencia que empiece en 1 y recorra todos los naturales hasta el 10. Después crea otra secuencia de longitud 7 que todos los números sean 3.

  • Solución:
1:10
##  [1]  1  2  3  4  5  6  7  8  9 10
rep(3, 7) # secuencia repetida
## [1] 3 3 3 3 3 3 3

 

📝Ejercicio 8: crea una secuencia que repita 5 veces el patrón 1, 2, 3. Después crea otra que repita dicho patrón pero de forma intercalada, con 5 veces 1, después 5 veces 2 y después 5 veces 3.

  • Solución:
rep(c(1, 2, 3), 5) # repetimos patrón (1, 2, 3) 5 veces
##  [1] 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3
rep(c(1, 2, 3), each = 5) # repetimos patrón alternado
##  [1] 1 1 1 1 1 2 2 2 2 2 3 3 3 3 3

 

📝Ejercicio 9: crea un vector con las edades de cuatro conocidos o familiares. Tras ello, determina cuáles de ellos tienen menos de 20 años, 30 años o más, menos de 40 años y más de 65 años.

  • Solución:
edades <- c(27, 32, 60, 61) # en mi caso, por ejemplo
edades < 20 # menos de 20 años
## [1] FALSE FALSE FALSE FALSE
edades >= 30 # 30 años o más
## [1] FALSE  TRUE  TRUE  TRUE
edades < 40 # menos de 40 años
## [1]  TRUE  TRUE FALSE FALSE
edades > 65 # más de 65 años
## [1] FALSE FALSE FALSE FALSE

Operaciones con vectores

(haz click en las flechas para ver soluciones)

📝Ejercicio 1: define de nuevo el vector vector_num definido como un vector que contenga los números 1, 10, -1 y 2) y calcula su suma del vector.

  • Solución:
# Vector de números
vector_num <- c(1, 10, -1, 2)

# Suma
sum(vector_num)
## [1] 12

 

📝Ejercicio 2: define otro vector vector_num2 que contenga los números 5, -7, 8, -3, y haz la suma de vector_num y vector_num2.

  • Solución:
# Vector de números
vector_num2 <- c(5, -7, 8, -3)

# Suma
vector_num + vector_num2
## [1]  6  3  7 -1

 

📝Ejercicio 3: calcula el número de elementos mayores que 0 del resultado de la suma de vector_num y vector_num2.

  • Solución:
# Vector de números
vector_suma <- vector_num + vector_num2

# Suma
sum(vector_suma > 0)
## [1] 3

 

📝Ejercicio 4: calcula la versión ordenada del vector vector_num.

  • Solución:
# Ordenamos el vector (con sort)
sort(vector_num)
## [1] -1  1  2 10
# Ordenamos el vector  (con order)
vector_num[order(vector_num)]
## [1] -1  1  2 10

 

📝Ejercicio 5: encuentra del vector vector_num original el lugar (el índice) que ocupa su mínimo y su máximo.

  • Solución:
vector_num <- c(1, 10, -1, 2)

# Encontrando el lugar que ocupa el máximo y mínimo
which.max(vector_num)
## [1] 2
which.min(vector_num)
## [1] 3

 

📝Ejercicio 6: encuentra del vector vector_num los elementos mayores que 1 y menores que 7. Encuentra una forma de averiguar si todos los elementos son o no positivos.

  • Solución:
# Vector lógico: mayores que 1 y menores que 7
vector_num > 1 & vector_num < 7
## [1] FALSE FALSE FALSE  TRUE
# ¿Son todos positivos?
all(vector_num > 0)
## [1] FALSE

 

📝Ejercicio 7: define el vector c(-1, 0, 4, 5, -2), calcula la raíz cuadrada del vector y determina que lugares son ausente de tipo NaN.

  • Solución:
# Vector
x <- c(-1, 0, 4, 5, -2)

# ¿Cuáles son ausentes tras aplicar la raíz cuadrada?
is.nan(sqrt(x))
## [1]  TRUE FALSE FALSE FALSE  TRUE

 

📝Ejercicio 8: define el vector de los primeros números impares (hasta el 21) y extrae los elementos que ocupan los lugares 1, 4, 5, 8. Elimina del vector el segundo elemento

  • Solución:
# Vector de impares (de 1 a 21 saltando de dos en dos)
x <- seq(1, 21, by = 2)

# Seleccionamos elementos
x[c(1, 4, 5, 8)]
## [1]  1  7  9 15
# Eliminamos elementos
y <- x[-2]
y
##  [1]  1  5  7  9 11 13 15 17 19 21

Estructuras de datos: matrices y tablas (data.frame)

(haz click en las flechas para ver soluciones)

Ejercicio 1: modifica el código para definir una matriz x de ceros de 3 filas y 7 columnas.

# Matriz
x <- matrix(0, nrow = 2, ncol = 3)
x

  • Solución:
# Matriz
x <- matrix(0, nrow = 3, ncol = 7)
x
##      [,1] [,2] [,3] [,4] [,5] [,6] [,7]
## [1,]    0    0    0    0    0    0    0
## [2,]    0    0    0    0    0    0    0
## [3,]    0    0    0    0    0    0    0

 

Ejercicio 2: a la matriz anterior, suma un 1 a cada número de la matriz y divide el resultado entre 5.

  • Solución:
(x + 1) / 5
##      [,1] [,2] [,3] [,4] [,5] [,6] [,7]
## [1,]  0.2  0.2  0.2  0.2  0.2  0.2  0.2
## [2,]  0.2  0.2  0.2  0.2  0.2  0.2  0.2
## [3,]  0.2  0.2  0.2  0.2  0.2  0.2  0.2

 

Ejercicio 3: tras definir la matriz x calcula su transpuesta y obtén sus dimensiones

  • Solución:
# Transpuesta
t(x)
##      [,1] [,2] [,3]
## [1,]    0    0    0
## [2,]    0    0    0
## [3,]    0    0    0
## [4,]    0    0    0
## [5,]    0    0    0
## [6,]    0    0    0
## [7,]    0    0    0
# Dimensiones transpuesta: pasa de ser 3x7 a 7x3
dim(t(x))
## [1] 7 3
ncol(t(x)) # número de columnas de la transpuesta
## [1] 3
nrow(t(x)) # número de filas de la transpuesta
## [1] 7

 

Ejercicio 4: el siguiente código define una matriz de dimensiones 4 x 3 y calcula la suma por columnas. Modifica el código para que realice la suma por filas.

# Matriz
matriz <- matrix(1:12, nrow = 4)

# Suma por columnas
apply(matriz, MARGIN = 2, FUN = "sum")
## [1] 10 26 42

  • Solución:
# Matriz
matriz <- matrix(1:12, nrow = 4)

# Suma por filas
apply(matriz, MARGIN = 1, FUN = "sum")
## [1] 15 18 21 24

 

Ejercicio 5: con la matriz anterior definida como matrix(1:12, nrow = 4), calcula la media de todos los elementos, la media de cada fila y la media de cada columna.

  • Solución:
# Matriz
matriz <- matrix(1:12, nrow = 4)

#  media de todos
mean(matriz)
## [1] 6.5
# Media por filas (MARGIN = 1 ya que es una operación por filas)
apply(matriz, MARGIN = 1, FUN = "mean")
## [1] 5 6 7 8
# Media por filas (MARGIN = 2 ya que es una operación por filas)
apply(matriz, MARGIN = 2, FUN = "mean")
## [1]  2.5  6.5 10.5

 

Ejercicio 6: el data.frame llamado airquality, del paquete {datasets}, contiene variables de la calidad del aire de la ciudad de Nueva York desde mayo hasta septiembre de 1973. Obtén el nombre de las variables.

  • Solución:
library(datasets)
names(airquality)
## [1] "Ozone"   "Solar.R" "Wind"    "Temp"    "Month"   "Day"

 

Ejercicio 7: obtén las dimensiones del conjunto de datos. ¿Cuántas variables hay? ¿Cuántos días se han medido?

  • Solución:
# Dimensiones
dim(airquality)
## [1] 153   6
nrow(airquality)
## [1] 153
ncol(airquality)
## [1] 6

 

Ejercicio 8: modifica el código inferior para que nos filtre solo los datos del mes de julio.

# Filtramos filas
filtro_fila <- subset(., subset = Month < 6)
filtro_fila

  • Solución:
# Filtramos filas
filtro_fila <- subset(airquality, subset = Month == 7)
filtro_fila
##    Ozone Solar.R Wind Temp Month Day
## 62   135     269  4.1   84     7   1
## 63    49     248  9.2   85     7   2
## 64    32     236  9.2   81     7   3
## 65    NA     101 10.9   84     7   4
## 66    64     175  4.6   83     7   5
## 67    40     314 10.9   83     7   6
## 68    77     276  5.1   88     7   7
## 69    97     267  6.3   92     7   8
## 70    97     272  5.7   92     7   9
## 71    85     175  7.4   89     7  10
## 72    NA     139  8.6   82     7  11
## 73    10     264 14.3   73     7  12
## 74    27     175 14.9   81     7  13
## 75    NA     291 14.9   91     7  14
## 76     7      48 14.3   80     7  15
## 77    48     260  6.9   81     7  16
## 78    35     274 10.3   82     7  17
## 79    61     285  6.3   84     7  18
## 80    79     187  5.1   87     7  19
## 81    63     220 11.5   85     7  20
## 82    16       7  6.9   74     7  21
## 83    NA     258  9.7   81     7  22
## 84    NA     295 11.5   82     7  23
## 85    80     294  8.6   86     7  24
## 86   108     223  8.0   85     7  25
## 87    20      81  8.6   82     7  26
## 88    52      82 12.0   86     7  27
## 89    82     213  7.4   88     7  28
## 90    50     275  7.4   86     7  29
## 91    64     253  7.4   83     7  30
## 92    59     254  9.2   81     7  31

 

Ejercicio 9: del conjunto airquality selecciona aquellos datos que no sean ni de julio ni de agosto.

  • Solución:
# Filtramos filas
filtro_fila <-
  subset(airquality, subset = !(Month %in% c(7, 8)))
filtro_fila
##     Ozone Solar.R Wind Temp Month Day
## 1      41     190  7.4   67     5   1
## 2      36     118  8.0   72     5   2
## 3      12     149 12.6   74     5   3
## 4      18     313 11.5   62     5   4
## 5      NA      NA 14.3   56     5   5
## 6      28      NA 14.9   66     5   6
## 7      23     299  8.6   65     5   7
## 8      19      99 13.8   59     5   8
## 9       8      19 20.1   61     5   9
## 10     NA     194  8.6   69     5  10
## 11      7      NA  6.9   74     5  11
## 12     16     256  9.7   69     5  12
## 13     11     290  9.2   66     5  13
## 14     14     274 10.9   68     5  14
## 15     18      65 13.2   58     5  15
## 16     14     334 11.5   64     5  16
## 17     34     307 12.0   66     5  17
## 18      6      78 18.4   57     5  18
## 19     30     322 11.5   68     5  19
## 20     11      44  9.7   62     5  20
## 21      1       8  9.7   59     5  21
## 22     11     320 16.6   73     5  22
## 23      4      25  9.7   61     5  23
## 24     32      92 12.0   61     5  24
## 25     NA      66 16.6   57     5  25
## 26     NA     266 14.9   58     5  26
## 27     NA      NA  8.0   57     5  27
## 28     23      13 12.0   67     5  28
## 29     45     252 14.9   81     5  29
## 30    115     223  5.7   79     5  30
## 31     37     279  7.4   76     5  31
## 32     NA     286  8.6   78     6   1
## 33     NA     287  9.7   74     6   2
## 34     NA     242 16.1   67     6   3
## 35     NA     186  9.2   84     6   4
## 36     NA     220  8.6   85     6   5
## 37     NA     264 14.3   79     6   6
## 38     29     127  9.7   82     6   7
## 39     NA     273  6.9   87     6   8
## 40     71     291 13.8   90     6   9
## 41     39     323 11.5   87     6  10
## 42     NA     259 10.9   93     6  11
## 43     NA     250  9.2   92     6  12
## 44     23     148  8.0   82     6  13
## 45     NA     332 13.8   80     6  14
## 46     NA     322 11.5   79     6  15
## 47     21     191 14.9   77     6  16
## 48     37     284 20.7   72     6  17
## 49     20      37  9.2   65     6  18
## 50     12     120 11.5   73     6  19
## 51     13     137 10.3   76     6  20
## 52     NA     150  6.3   77     6  21
## 53     NA      59  1.7   76     6  22
## 54     NA      91  4.6   76     6  23
## 55     NA     250  6.3   76     6  24
## 56     NA     135  8.0   75     6  25
## 57     NA     127  8.0   78     6  26
## 58     NA      47 10.3   73     6  27
## 59     NA      98 11.5   80     6  28
## 60     NA      31 14.9   77     6  29
## 61     NA     138  8.0   83     6  30
## 124    96     167  6.9   91     9   1
## 125    78     197  5.1   92     9   2
## 126    73     183  2.8   93     9   3
## 127    91     189  4.6   93     9   4
## 128    47      95  7.4   87     9   5
## 129    32      92 15.5   84     9   6
## 130    20     252 10.9   80     9   7
## 131    23     220 10.3   78     9   8
## 132    21     230 10.9   75     9   9
## 133    24     259  9.7   73     9  10
## 134    44     236 14.9   81     9  11
## 135    21     259 15.5   76     9  12
## 136    28     238  6.3   77     9  13
## 137     9      24 10.9   71     9  14
## 138    13     112 11.5   71     9  15
## 139    46     237  6.9   78     9  16
## 140    18     224 13.8   67     9  17
## 141    13      27 10.3   76     9  18
## 142    24     238 10.3   68     9  19
## 143    16     201  8.0   82     9  20
## 144    13     238 12.6   64     9  21
## 145    23      14  9.2   71     9  22
## 146    36     139 10.3   81     9  23
## 147     7      49 10.3   69     9  24
## 148    14      20 16.6   63     9  25
## 149    30     193  6.9   70     9  26
## 150    NA     145 13.2   77     9  27
## 151    14     191 14.3   75     9  28
## 152    18     131  8.0   76     9  29
## 153    20     223 11.5   68     9  30

 

Ejercicio 10: modifica el siguiente código para quedarte solo con las variable Ozone y Temp.

filtro_col <- subset(.,  select = c("Ozone"))
filtro_col

  • Solución:
# Filtramos columnas
filtro_col <- subset(airquality,  select = c("Ozone", "Temp"))
filtro_col
##     Ozone Temp
## 1      41   67
## 2      36   72
## 3      12   74
## 4      18   62
## 5      NA   56
## 6      28   66
## 7      23   65
## 8      19   59
## 9       8   61
## 10     NA   69
## 11      7   74
## 12     16   69
## 13     11   66
## 14     14   68
## 15     18   58
## 16     14   64
## 17     34   66
## 18      6   57
## 19     30   68
## 20     11   62
## 21      1   59
## 22     11   73
## 23      4   61
## 24     32   61
## 25     NA   57
## 26     NA   58
## 27     NA   57
## 28     23   67
## 29     45   81
## 30    115   79
## 31     37   76
## 32     NA   78
## 33     NA   74
## 34     NA   67
## 35     NA   84
## 36     NA   85
## 37     NA   79
## 38     29   82
## 39     NA   87
## 40     71   90
## 41     39   87
## 42     NA   93
## 43     NA   92
## 44     23   82
## 45     NA   80
## 46     NA   79
## 47     21   77
## 48     37   72
## 49     20   65
## 50     12   73
## 51     13   76
## 52     NA   77
## 53     NA   76
## 54     NA   76
## 55     NA   76
## 56     NA   75
## 57     NA   78
## 58     NA   73
## 59     NA   80
## 60     NA   77
## 61     NA   83
## 62    135   84
## 63     49   85
## 64     32   81
## 65     NA   84
## 66     64   83
## 67     40   83
## 68     77   88
## 69     97   92
## 70     97   92
## 71     85   89
## 72     NA   82
## 73     10   73
## 74     27   81
## 75     NA   91
## 76      7   80
## 77     48   81
## 78     35   82
## 79     61   84
## 80     79   87
## 81     63   85
## 82     16   74
## 83     NA   81
## 84     NA   82
## 85     80   86
## 86    108   85
## 87     20   82
## 88     52   86
## 89     82   88
## 90     50   86
## 91     64   83
## 92     59   81
## 93     39   81
## 94      9   81
## 95     16   82
## 96     78   86
## 97     35   85
## 98     66   87
## 99    122   89
## 100    89   90
## 101   110   90
## 102    NA   92
## 103    NA   86
## 104    44   86
## 105    28   82
## 106    65   80
## 107    NA   79
## 108    22   77
## 109    59   79
## 110    23   76
## 111    31   78
## 112    44   78
## 113    21   77
## 114     9   72
## 115    NA   75
## 116    45   79
## 117   168   81
## 118    73   86
## 119    NA   88
## 120    76   97
## 121   118   94
## 122    84   96
## 123    85   94
## 124    96   91
## 125    78   92
## 126    73   93
## 127    91   93
## 128    47   87
## 129    32   84
## 130    20   80
## 131    23   78
## 132    21   75
## 133    24   73
## 134    44   81
## 135    21   76
## 136    28   77
## 137     9   71
## 138    13   71
## 139    46   78
## 140    18   67
## 141    13   76
## 142    24   68
## 143    16   82
## 144    13   64
## 145    23   71
## 146    36   81
## 147     7   69
## 148    14   63
## 149    30   70
## 150    NA   77
## 151    14   75
## 152    18   76
## 153    20   68

 

Ejercicio 11: del conjunto airquality selecciona los datos de temperatura y viento de agosto.

  • Solución:
# Todo de una vez
filtro <- subset(airquality, subset = Month == 8,
                 select = c("Temp", "Wind"))
filtro
##     Temp Wind
## 93    81  6.9
## 94    81 13.8
## 95    82  7.4
## 96    86  6.9
## 97    85  7.4
## 98    87  4.6
## 99    89  4.0
## 100   90 10.3
## 101   90  8.0
## 102   92  8.6
## 103   86 11.5
## 104   86 11.5
## 105   82 11.5
## 106   80  9.7
## 107   79 11.5
## 108   77 10.3
## 109   79  6.3
## 110   76  7.4
## 111   78 10.9
## 112   78 10.3
## 113   77 15.5
## 114   72 14.3
## 115   75 12.6
## 116   79  9.7
## 117   81  3.4
## 118   86  8.0
## 119   88  5.7
## 120   97  9.7
## 121   94  2.3
## 122   96  6.3
## 123   94  6.3

 

Ejercicio 12: calcula el número de filas borradas del ejercicio anterior. Tras hacer todo ello, traduce a castellano el nombre de las columnas del data.frame filtrado.

  • Solución:
# Filas borradas
nrow(airquality) - nrow(filtro)
## [1] 122
# Cambiamos nombres a castellano del conjunto filtrado
names(filtro) <- c("temperatura", "viento")

 

Ejercicio 13: añade a los datos originales una columna con la fecha completa (recuerda que es del año 1973 todas las observaciones.

  • Solución:
# Construimos las fechas (pegamos año-mes-día con "-")
fechas <- 
  as.Date(paste("1973", airquality$Month, airquality$Day,
                sep = "-"))

# Añadimos
data.frame(airquality, fechas)
##     Ozone Solar.R Wind Temp Month Day     fechas
## 1      41     190  7.4   67     5   1 1973-05-01
## 2      36     118  8.0   72     5   2 1973-05-02
## 3      12     149 12.6   74     5   3 1973-05-03
## 4      18     313 11.5   62     5   4 1973-05-04
## 5      NA      NA 14.3   56     5   5 1973-05-05
## 6      28      NA 14.9   66     5   6 1973-05-06
## 7      23     299  8.6   65     5   7 1973-05-07
## 8      19      99 13.8   59     5   8 1973-05-08
## 9       8      19 20.1   61     5   9 1973-05-09
## 10     NA     194  8.6   69     5  10 1973-05-10
## 11      7      NA  6.9   74     5  11 1973-05-11
## 12     16     256  9.7   69     5  12 1973-05-12
## 13     11     290  9.2   66     5  13 1973-05-13
## 14     14     274 10.9   68     5  14 1973-05-14
## 15     18      65 13.2   58     5  15 1973-05-15
## 16     14     334 11.5   64     5  16 1973-05-16
## 17     34     307 12.0   66     5  17 1973-05-17
## 18      6      78 18.4   57     5  18 1973-05-18
## 19     30     322 11.5   68     5  19 1973-05-19
## 20     11      44  9.7   62     5  20 1973-05-20
## 21      1       8  9.7   59     5  21 1973-05-21
## 22     11     320 16.6   73     5  22 1973-05-22
## 23      4      25  9.7   61     5  23 1973-05-23
## 24     32      92 12.0   61     5  24 1973-05-24
## 25     NA      66 16.6   57     5  25 1973-05-25
## 26     NA     266 14.9   58     5  26 1973-05-26
## 27     NA      NA  8.0   57     5  27 1973-05-27
## 28     23      13 12.0   67     5  28 1973-05-28
## 29     45     252 14.9   81     5  29 1973-05-29
## 30    115     223  5.7   79     5  30 1973-05-30
## 31     37     279  7.4   76     5  31 1973-05-31
## 32     NA     286  8.6   78     6   1 1973-06-01
## 33     NA     287  9.7   74     6   2 1973-06-02
## 34     NA     242 16.1   67     6   3 1973-06-03
## 35     NA     186  9.2   84     6   4 1973-06-04
## 36     NA     220  8.6   85     6   5 1973-06-05
## 37     NA     264 14.3   79     6   6 1973-06-06
## 38     29     127  9.7   82     6   7 1973-06-07
## 39     NA     273  6.9   87     6   8 1973-06-08
## 40     71     291 13.8   90     6   9 1973-06-09
## 41     39     323 11.5   87     6  10 1973-06-10
## 42     NA     259 10.9   93     6  11 1973-06-11
## 43     NA     250  9.2   92     6  12 1973-06-12
## 44     23     148  8.0   82     6  13 1973-06-13
## 45     NA     332 13.8   80     6  14 1973-06-14
## 46     NA     322 11.5   79     6  15 1973-06-15
## 47     21     191 14.9   77     6  16 1973-06-16
## 48     37     284 20.7   72     6  17 1973-06-17
## 49     20      37  9.2   65     6  18 1973-06-18
## 50     12     120 11.5   73     6  19 1973-06-19
## 51     13     137 10.3   76     6  20 1973-06-20
## 52     NA     150  6.3   77     6  21 1973-06-21
## 53     NA      59  1.7   76     6  22 1973-06-22
## 54     NA      91  4.6   76     6  23 1973-06-23
## 55     NA     250  6.3   76     6  24 1973-06-24
## 56     NA     135  8.0   75     6  25 1973-06-25
## 57     NA     127  8.0   78     6  26 1973-06-26
## 58     NA      47 10.3   73     6  27 1973-06-27
## 59     NA      98 11.5   80     6  28 1973-06-28
## 60     NA      31 14.9   77     6  29 1973-06-29
## 61     NA     138  8.0   83     6  30 1973-06-30
## 62    135     269  4.1   84     7   1 1973-07-01
## 63     49     248  9.2   85     7   2 1973-07-02
## 64     32     236  9.2   81     7   3 1973-07-03
## 65     NA     101 10.9   84     7   4 1973-07-04
## 66     64     175  4.6   83     7   5 1973-07-05
## 67     40     314 10.9   83     7   6 1973-07-06
## 68     77     276  5.1   88     7   7 1973-07-07
## 69     97     267  6.3   92     7   8 1973-07-08
## 70     97     272  5.7   92     7   9 1973-07-09
## 71     85     175  7.4   89     7  10 1973-07-10
## 72     NA     139  8.6   82     7  11 1973-07-11
## 73     10     264 14.3   73     7  12 1973-07-12
## 74     27     175 14.9   81     7  13 1973-07-13
## 75     NA     291 14.9   91     7  14 1973-07-14
## 76      7      48 14.3   80     7  15 1973-07-15
## 77     48     260  6.9   81     7  16 1973-07-16
## 78     35     274 10.3   82     7  17 1973-07-17
## 79     61     285  6.3   84     7  18 1973-07-18
## 80     79     187  5.1   87     7  19 1973-07-19
## 81     63     220 11.5   85     7  20 1973-07-20
## 82     16       7  6.9   74     7  21 1973-07-21
## 83     NA     258  9.7   81     7  22 1973-07-22
## 84     NA     295 11.5   82     7  23 1973-07-23
## 85     80     294  8.6   86     7  24 1973-07-24
## 86    108     223  8.0   85     7  25 1973-07-25
## 87     20      81  8.6   82     7  26 1973-07-26
## 88     52      82 12.0   86     7  27 1973-07-27
## 89     82     213  7.4   88     7  28 1973-07-28
## 90     50     275  7.4   86     7  29 1973-07-29
## 91     64     253  7.4   83     7  30 1973-07-30
## 92     59     254  9.2   81     7  31 1973-07-31
## 93     39      83  6.9   81     8   1 1973-08-01
## 94      9      24 13.8   81     8   2 1973-08-02
## 95     16      77  7.4   82     8   3 1973-08-03
## 96     78      NA  6.9   86     8   4 1973-08-04
## 97     35      NA  7.4   85     8   5 1973-08-05
## 98     66      NA  4.6   87     8   6 1973-08-06
## 99    122     255  4.0   89     8   7 1973-08-07
## 100    89     229 10.3   90     8   8 1973-08-08
## 101   110     207  8.0   90     8   9 1973-08-09
## 102    NA     222  8.6   92     8  10 1973-08-10
## 103    NA     137 11.5   86     8  11 1973-08-11
## 104    44     192 11.5   86     8  12 1973-08-12
## 105    28     273 11.5   82     8  13 1973-08-13
## 106    65     157  9.7   80     8  14 1973-08-14
## 107    NA      64 11.5   79     8  15 1973-08-15
## 108    22      71 10.3   77     8  16 1973-08-16
## 109    59      51  6.3   79     8  17 1973-08-17
## 110    23     115  7.4   76     8  18 1973-08-18
## 111    31     244 10.9   78     8  19 1973-08-19
## 112    44     190 10.3   78     8  20 1973-08-20
## 113    21     259 15.5   77     8  21 1973-08-21
## 114     9      36 14.3   72     8  22 1973-08-22
## 115    NA     255 12.6   75     8  23 1973-08-23
## 116    45     212  9.7   79     8  24 1973-08-24
## 117   168     238  3.4   81     8  25 1973-08-25
## 118    73     215  8.0   86     8  26 1973-08-26
## 119    NA     153  5.7   88     8  27 1973-08-27
## 120    76     203  9.7   97     8  28 1973-08-28
## 121   118     225  2.3   94     8  29 1973-08-29
## 122    84     237  6.3   96     8  30 1973-08-30
## 123    85     188  6.3   94     8  31 1973-08-31
## 124    96     167  6.9   91     9   1 1973-09-01
## 125    78     197  5.1   92     9   2 1973-09-02
## 126    73     183  2.8   93     9   3 1973-09-03
## 127    91     189  4.6   93     9   4 1973-09-04
## 128    47      95  7.4   87     9   5 1973-09-05
## 129    32      92 15.5   84     9   6 1973-09-06
## 130    20     252 10.9   80     9   7 1973-09-07
## 131    23     220 10.3   78     9   8 1973-09-08
## 132    21     230 10.9   75     9   9 1973-09-09
## 133    24     259  9.7   73     9  10 1973-09-10
## 134    44     236 14.9   81     9  11 1973-09-11
## 135    21     259 15.5   76     9  12 1973-09-12
## 136    28     238  6.3   77     9  13 1973-09-13
## 137     9      24 10.9   71     9  14 1973-09-14
## 138    13     112 11.5   71     9  15 1973-09-15
## 139    46     237  6.9   78     9  16 1973-09-16
## 140    18     224 13.8   67     9  17 1973-09-17
## 141    13      27 10.3   76     9  18 1973-09-18
## 142    24     238 10.3   68     9  19 1973-09-19
## 143    16     201  8.0   82     9  20 1973-09-20
## 144    13     238 12.6   64     9  21 1973-09-21
## 145    23      14  9.2   71     9  22 1973-09-22
## 146    36     139 10.3   81     9  23 1973-09-23
## 147     7      49 10.3   69     9  24 1973-09-24
## 148    14      20 16.6   63     9  25 1973-09-25
## 149    30     193  6.9   70     9  26 1973-09-26
## 150    NA     145 13.2   77     9  27 1973-09-27
## 151    14     191 14.3   75     9  28 1973-09-28
## 152    18     131  8.0   76     9  29 1973-09-29
## 153    20     223 11.5   68     9  30 1973-09-30

 

Repaso: empezando a trastear datos

1. ¿Cómo cargarías los datos sabiendo su nombre y el paquete en el que está?

 

Nuestros datos se llaman swiss y son del paquete {datasets}, así que lo primero que debemos hacer es instalar el paquete (en caso de no haberlo hecho aún, con install.packages("datasets")), después llamar a ese paquete (tenemos el libro comprado y lo sacamos de la estantería) con library(datasets) y escribir el nombre del conjunto de datos para mostrarlo.

library(datasets)
swiss
##              Fertility Agriculture Examination Education Catholic
## Courtelary        80.2        17.0          15        12     9.96
## Delemont          83.1        45.1           6         9    84.84
## Franches-Mnt      92.5        39.7           5         5    93.40
## Moutier           85.8        36.5          12         7    33.77
## Neuveville        76.9        43.5          17        15     5.16
## Porrentruy        76.1        35.3           9         7    90.57
## Broye             83.8        70.2          16         7    92.85
## Glane             92.4        67.8          14         8    97.16
## Gruyere           82.4        53.3          12         7    97.67
## Sarine            82.9        45.2          16        13    91.38
## Veveyse           87.1        64.5          14         6    98.61
## Aigle             64.1        62.0          21        12     8.52
## Aubonne           66.9        67.5          14         7     2.27
## Avenches          68.9        60.7          19        12     4.43
## Cossonay          61.7        69.3          22         5     2.82
## Echallens         68.3        72.6          18         2    24.20
## Grandson          71.7        34.0          17         8     3.30
## Lausanne          55.7        19.4          26        28    12.11
## La Vallee         54.3        15.2          31        20     2.15
## Lavaux            65.1        73.0          19         9     2.84
## Morges            65.5        59.8          22        10     5.23
## Moudon            65.0        55.1          14         3     4.52
## Nyone             56.6        50.9          22        12    15.14
## Orbe              57.4        54.1          20         6     4.20
## Oron              72.5        71.2          12         1     2.40
## Payerne           74.2        58.1          14         8     5.23
## Paysd'enhaut      72.0        63.5           6         3     2.56
## Rolle             60.5        60.8          16        10     7.72
## Vevey             58.3        26.8          25        19    18.46
## Yverdon           65.4        49.5          15         8     6.10
## Conthey           75.5        85.9           3         2    99.71
## Entremont         69.3        84.9           7         6    99.68
## Herens            77.3        89.7           5         2   100.00
## Martigwy          70.5        78.2          12         6    98.96
## Monthey           79.4        64.9           7         3    98.22
## St Maurice        65.0        75.9           9         9    99.06
## Sierre            92.2        84.6           3         3    99.46
## Sion              79.3        63.1          13        13    96.83
## Boudry            70.4        38.4          26        12     5.62
## La Chauxdfnd      65.7         7.7          29        11    13.79
## Le Locle          72.7        16.7          22        13    11.22
## Neuchatel         64.4        17.6          35        32    16.92
## Val de Ruz        77.6        37.6          15         7     4.97
## ValdeTravers      67.6        18.7          25         7     8.65
## V. De Geneve      35.0         1.2          37        53    42.34
## Rive Droite       44.7        46.6          16        29    50.43
## Rive Gauche       42.8        27.7          22        29    58.33
##              Infant.Mortality
## Courtelary               22.2
## Delemont                 22.2
## Franches-Mnt             20.2
## Moutier                  20.3
## Neuveville               20.6
## Porrentruy               26.6
## Broye                    23.6
## Glane                    24.9
## Gruyere                  21.0
## Sarine                   24.4
## Veveyse                  24.5
## Aigle                    16.5
## Aubonne                  19.1
## Avenches                 22.7
## Cossonay                 18.7
## Echallens                21.2
## Grandson                 20.0
## Lausanne                 20.2
## La Vallee                10.8
## Lavaux                   20.0
## Morges                   18.0
## Moudon                   22.4
## Nyone                    16.7
## Orbe                     15.3
## Oron                     21.0
## Payerne                  23.8
## Paysd'enhaut             18.0
## Rolle                    16.3
## Vevey                    20.9
## Yverdon                  22.5
## Conthey                  15.1
## Entremont                19.8
## Herens                   18.3
## Martigwy                 19.4
## Monthey                  20.2
## St Maurice               17.8
## Sierre                   16.3
## Sion                     18.1
## Boudry                   20.3
## La Chauxdfnd             20.5
## Le Locle                 18.9
## Neuchatel                23.0
## Val de Ruz               20.0
## ValdeTravers             19.5
## V. De Geneve             18.0
## Rive Droite              18.2
## Rive Gauche              19.3

Podríamos no pedirle el libro entero sino solo esa página, de ese conjunto de datos, usando datasets::swiss (sin hacer uso del library() previo).

datasets::swiss

 

2. Tenemos los datos guardados en swiss, ¿qué tipo de objeto es?

 

Al mostrarlos ya lo habrás intuido pero nuestro conjunto swiss es de tipo data.frame. Para comprobarlo podemos usar la función class().

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

Si somos un poco observadores/as vemos que todas las variables parecen numéricas así que…podríamos tener una matriz de números. ¿Cómo convertimos los datos a una matriz?

as.matrix(swiss)
##              Fertility Agriculture Examination Education Catholic
## Courtelary        80.2        17.0          15        12     9.96
## Delemont          83.1        45.1           6         9    84.84
## Franches-Mnt      92.5        39.7           5         5    93.40
## Moutier           85.8        36.5          12         7    33.77
## Neuveville        76.9        43.5          17        15     5.16
## Porrentruy        76.1        35.3           9         7    90.57
## Broye             83.8        70.2          16         7    92.85
## Glane             92.4        67.8          14         8    97.16
## Gruyere           82.4        53.3          12         7    97.67
## Sarine            82.9        45.2          16        13    91.38
## Veveyse           87.1        64.5          14         6    98.61
## Aigle             64.1        62.0          21        12     8.52
## Aubonne           66.9        67.5          14         7     2.27
## Avenches          68.9        60.7          19        12     4.43
## Cossonay          61.7        69.3          22         5     2.82
## Echallens         68.3        72.6          18         2    24.20
## Grandson          71.7        34.0          17         8     3.30
## Lausanne          55.7        19.4          26        28    12.11
## La Vallee         54.3        15.2          31        20     2.15
## Lavaux            65.1        73.0          19         9     2.84
## Morges            65.5        59.8          22        10     5.23
## Moudon            65.0        55.1          14         3     4.52
## Nyone             56.6        50.9          22        12    15.14
## Orbe              57.4        54.1          20         6     4.20
## Oron              72.5        71.2          12         1     2.40
## Payerne           74.2        58.1          14         8     5.23
## Paysd'enhaut      72.0        63.5           6         3     2.56
## Rolle             60.5        60.8          16        10     7.72
## Vevey             58.3        26.8          25        19    18.46
## Yverdon           65.4        49.5          15         8     6.10
## Conthey           75.5        85.9           3         2    99.71
## Entremont         69.3        84.9           7         6    99.68
## Herens            77.3        89.7           5         2   100.00
## Martigwy          70.5        78.2          12         6    98.96
## Monthey           79.4        64.9           7         3    98.22
## St Maurice        65.0        75.9           9         9    99.06
## Sierre            92.2        84.6           3         3    99.46
## Sion              79.3        63.1          13        13    96.83
## Boudry            70.4        38.4          26        12     5.62
## La Chauxdfnd      65.7         7.7          29        11    13.79
## Le Locle          72.7        16.7          22        13    11.22
## Neuchatel         64.4        17.6          35        32    16.92
## Val de Ruz        77.6        37.6          15         7     4.97
## ValdeTravers      67.6        18.7          25         7     8.65
## V. De Geneve      35.0         1.2          37        53    42.34
## Rive Droite       44.7        46.6          16        29    50.43
## Rive Gauche       42.8        27.7          22        29    58.33
##              Infant.Mortality
## Courtelary               22.2
## Delemont                 22.2
## Franches-Mnt             20.2
## Moutier                  20.3
## Neuveville               20.6
## Porrentruy               26.6
## Broye                    23.6
## Glane                    24.9
## Gruyere                  21.0
## Sarine                   24.4
## Veveyse                  24.5
## Aigle                    16.5
## Aubonne                  19.1
## Avenches                 22.7
## Cossonay                 18.7
## Echallens                21.2
## Grandson                 20.0
## Lausanne                 20.2
## La Vallee                10.8
## Lavaux                   20.0
## Morges                   18.0
## Moudon                   22.4
## Nyone                    16.7
## Orbe                     15.3
## Oron                     21.0
## Payerne                  23.8
## Paysd'enhaut             18.0
## Rolle                    16.3
## Vevey                    20.9
## Yverdon                  22.5
## Conthey                  15.1
## Entremont                19.8
## Herens                   18.3
## Martigwy                 19.4
## Monthey                  20.2
## St Maurice               17.8
## Sierre                   16.3
## Sion                     18.1
## Boudry                   20.3
## La Chauxdfnd             20.5
## Le Locle                 18.9
## Neuchatel                23.0
## Val de Ruz               20.0
## ValdeTravers             19.5
## V. De Geneve             18.0
## Rive Droite              18.2
## Rive Gauche              19.3
## [1] "matrix"

 

3. ¿Cómo podríamos tener una descripción detallada de los datos?

 

La forma más inmediata es hacerlo es con la función ? swiss, que nos permite ver la documentación en el panel de ayuda.

? swiss

También podemos ver el nombre de las columnas con names() y el nombre de las filas con row.names()

names(swiss)
## [1] "Fertility"        "Agriculture"      "Examination"      "Education"       
## [5] "Catholic"         "Infant.Mortality"
row.names(swiss)
##  [1] "Courtelary"   "Delemont"     "Franches-Mnt" "Moutier"      "Neuveville"  
##  [6] "Porrentruy"   "Broye"        "Glane"        "Gruyere"      "Sarine"      
## [11] "Veveyse"      "Aigle"        "Aubonne"      "Avenches"     "Cossonay"    
## [16] "Echallens"    "Grandson"     "Lausanne"     "La Vallee"    "Lavaux"      
## [21] "Morges"       "Moudon"       "Nyone"        "Orbe"         "Oron"        
## [26] "Payerne"      "Paysd'enhaut" "Rolle"        "Vevey"        "Yverdon"     
## [31] "Conthey"      "Entremont"    "Herens"       "Martigwy"     "Monthey"     
## [36] "St Maurice"   "Sierre"       "Sion"         "Boudry"       "La Chauxdfnd"
## [41] "Le Locle"     "Neuchatel"    "Val de Ruz"   "ValdeTravers" "V. De Geneve"
## [46] "Rive Droite"  "Rive Gauche"

Los datos representan algunos indicadores de fertilidad y socioeconómicos (estandarizados, entre 0 y 100) de las 47 provincias francoparlantes de Suiza, con datos del año 1888. Como podemos leer en la ayuda, en la web https://opr.princeton.edu/archive/pefp/switz.aspx tenemos los datos de 182 distritos para dicho año.

 

4. ¿Cómo podríamos «ver» los datos? ¿Cuántas provincias hay incluidas? ¿Cuántas variables han sido medidas en cada una de ellas?

 

Podemos hacerlo de varias maneras, y una de ellas es pedirle una cabecera de la tabla (las primeras filas) con head().

head(swiss)
##              Fertility Agriculture Examination Education Catholic
## Courtelary        80.2        17.0          15        12     9.96
## Delemont          83.1        45.1           6         9    84.84
## Franches-Mnt      92.5        39.7           5         5    93.40
## Moutier           85.8        36.5          12         7    33.77
## Neuveville        76.9        43.5          17        15     5.16
## Porrentruy        76.1        35.3           9         7    90.57
##              Infant.Mortality
## Courtelary               22.2
## Delemont                 22.2
## Franches-Mnt             20.2
## Moutier                  20.3
## Neuveville               20.6
## Porrentruy               26.6

También podemos ver una versión «excelizada» de los datos con `View()

View(swiss)

Para ver las dimensiones de los datos podemos recurrir a dim() (nos dará un vector de longitud 2 con el número de filas y columnas) o a nrow() y ncol()

dim(swiss)
## [1] 47  6
nrow(swiss)
## [1] 47
ncol(swiss)
## [1] 6

 

5. ¿Cómo podríamos definir una nueva variable de tipo texto con los nombres de filas que obtenemos de row.names()?

 

La función row.names() nos devuelve los nombres de las filas, que vamos a guardar en una variable (por ejemplo, en nombres).

nombres <- row.names(swiss)
nombres
##  [1] "Courtelary"   "Delemont"     "Franches-Mnt" "Moutier"      "Neuveville"  
##  [6] "Porrentruy"   "Broye"        "Glane"        "Gruyere"      "Sarine"      
## [11] "Veveyse"      "Aigle"        "Aubonne"      "Avenches"     "Cossonay"    
## [16] "Echallens"    "Grandson"     "Lausanne"     "La Vallee"    "Lavaux"      
## [21] "Morges"       "Moudon"       "Nyone"        "Orbe"         "Oron"        
## [26] "Payerne"      "Paysd'enhaut" "Rolle"        "Vevey"        "Yverdon"     
## [31] "Conthey"      "Entremont"    "Herens"       "Martigwy"     "Monthey"     
## [36] "St Maurice"   "Sierre"       "Sion"         "Boudry"       "La Chauxdfnd"
## [41] "Le Locle"     "Neuchatel"    "Val de Ruz"   "ValdeTravers" "V. De Geneve"
## [46] "Rive Droite"  "Rive Gauche"

Estructuras condicionales

(haz click en las flechas para ver soluciones)

📝Ejercicio 1: modifica el código inferior para imprimir un mensaje por pantalla si todos los datos del conjunto airquality son de meses que no sean enero.

library(datasets) # paquete con los adtos
mes <- airquality$Month

if (mes == 2) {
  
  print("Ningún dato es del mes de enero")
  
}

  • Solución:
library(datasets) # paquete con los datos
mes <- airquality$Month

if (all(mes != 1)) { # todos con mes distinto de 1
  
  print("Ningún dato es del mes de enero")
  
}
## [1] "Ningún dato es del mes de enero"

 

📝Ejercicio 2: modifica el código inferior para imprimir un mensaje por pantalla si alguno de los registros tiene una temperatura mayor a 90 (Farenheit).

temperatura <- airquality$Temp

if (temperatura  == 100) {
  
  print("Alguno de los registros tiene temperatura superior a 90 Farenheit")
  
}

  • Solución:
temperatura <- airquality$Temp

if (any(temperatura > 90)) {
  
  print("Alguno de los registros tiene temperatura superior a 90 Farenheit")
  
}
## [1] "Alguno de los registros tiene temperatura superior a 90 Farenheit"

 

📝Ejercicio 3: modifica el código inferior para imprimir un mensaje por pantalla si alguno de los días supera la temperatura de 100.

temperatura <- airquality$Temp

if (all(temperatura < 50)) {
  
  print("Alguno de los registros tiene temperatura superior a 100 Farenheit")
  
}

  • Solución:
temperatura <- airquality$Temp

if (any(temperatura > 100)) { # nos basta con uno
  
  print("Alguno de los registros tiene temperatura superior a 100 Farenheit")
  
}

No imprime nada porque ninguno cumple la condición.

 

📝Ejercicio 4: del paquete lubridate, la función hour() nos devuelve la hora de una fecha dada, y la función now() nos devuelve fecha y hora del momento actual. Con ambas funciones, y usando if, imprime por pantalla "buenas noches" solo a partir de las 21 horas.

  • Solución:
# Cargamos librería
library(lubridate)

# Fecha-hora actual
fecha_actual <- now()

# Estructura if
if (hour(fecha_actual) > 21) {
  
  cat("Buenas noches") # print/cat dos formas de imprimir por pantalla
}

 

📝Ejercicio 5: con las funciones del ejercicio anterior, y usando una estructura if-else, imprime por pantalla "buenos días" (de 6 a 14 horas), "buenas tardes" (de 14 a 21 horas) o "buenas noches" (de las 21 a las 6 horas).

  • Solución:
# Fecha actual
fecha_actual <- now()

# Estructura if-else
if (hour(fecha_actual) > 6 & hour(fecha_actual) < 14) {
  
  cat("Buenos días")
  
} else if (hour(fecha_actual) > 14 & hour(fecha_actual) < 21) {
  
  cat("Buenas tardes")
  
} else {
  
  cat("Buenas noches")
}
## Buenas noches

 

📝Ejercicio 6: realiza el ejercicio anterior pero sin estructura de llaves, de forma concisa con ifelse(). Mira la ayuda si la necesitases poniendo ? ifelse.

  • Solución:
# Fecha actual
fecha_actual <- now()

# Estructura if-else
cat(ifelse(hour(fecha_actual) > 6 & hour(fecha_actual) < 14,
           "Buenos días",
           ifelse(hour(fecha_actual) > 14 &
                    hour(fecha_actual) < 21,
                  "Buenas tardes", "Buenas noches")))
## Buenas noches

 

Bucles

(haz click en las flechas para ver soluciones)

📝Ejercicio 1: modifica el código interior para diseñar un bucle for de 5 iteraciones que recorra los 5 primeros impares y les sume uno.

for (i in 1:5) {
  
  print(i)
}
## [1] 1
## [1] 2
## [1] 3
## [1] 4
## [1] 5

  • Solución:
# Una forma
for (i in seq(1, 9, by = 2)) {
  
  print(i + 1)
}
## [1] 2
## [1] 4
## [1] 6
## [1] 8
## [1] 10
# Otra
for (i in c(1, 3, 5, 7, 9)) {
  
  print(i + 1)
}
## [1] 2
## [1] 4
## [1] 6
## [1] 8
## [1] 10

 

📝Ejercicio 2: modifica el código interior para diseñar un bucle while que parta con una variable conteo <- 1 y pare cuando llegue a 6.

conteo <- 1
while (conteo == 2) {
  
  print(conteo)
}

  • Solución:
conteo <- 1
while (conteo < 6) {
  
  print(conteo)
  conteo <- conteo <- conteo + 1
}
## [1] 1
## [1] 2
## [1] 3
## [1] 4
## [1] 5

 

📝Ejercicio 3: construye un bucle que recorra las primeras 8 filas del conjunto de datos MASS::mammals y que imprima el peso del animal (en kg) multiplicado por 1000 (gramos).

  • Solución:
for (i in 1:8) {
  
  print(MASS::mammals$body[i] * 1000)
}
## [1] 3385
## [1] 480
## [1] 1350
## [1] 465000
## [1] 36330
## [1] 27660
## [1] 14830
## [1] 1040

 

📝Ejercicio 4: diseña un bucle for de 200 iteraciones que, empezando en un valor inicial de 100 (euros), te sume 3€ si el número actual es par y te reste 5€ si es impar.

Un número par o impar: un número par será todo aquel número que al dividir entre 2, la división es exacta, es decir, que su resto es nulo. Por ejemplo, al dividir 5 entre 2, el resto es 1, pero al dividir 12 entre 2 el resto es 0. Para calcula ese resto usaremos la función %%.

5 %% 2
## [1] 1
12 %% 2
## [1] 0
23 %% 2
## [1] 1
46 %% 2
## [1] 0

  • Solución:
# dinero inicial
dinero <- 100

# Bucle for
for (i in 1:200) {
  
  dinero <- ifelse(dinero %% 2 == 0, dinero + 3, dinero  - 5)
  
}
dinero
## [1] -100

 

📝Ejercicio 5: diseña el anterior bucle pero guardando el dinero de cada iteración.

  • Solución:
# vector de importes
dinero <- rep(0, 201)
dinero[1] <- 100 # dinero inicial

# Bucle for
for (i in 2:201) {
  
  # si dinero[i - 1] es par o  impar
  dinero[i] <- ifelse(dinero[i - 1] %% 2 == 0, dinero[i - 1] + 3,
                      dinero[i - 1]  - 5)
  
}
dinero
##   [1]  100  103   98  101   96   99   94   97   92   95   90   93   88   91   86
##  [16]   89   84   87   82   85   80   83   78   81   76   79   74   77   72   75
##  [31]   70   73   68   71   66   69   64   67   62   65   60   63   58   61   56
##  [46]   59   54   57   52   55   50   53   48   51   46   49   44   47   42   45
##  [61]   40   43   38   41   36   39   34   37   32   35   30   33   28   31   26
##  [76]   29   24   27   22   25   20   23   18   21   16   19   14   17   12   15
##  [91]   10   13    8   11    6    9    4    7    2    5    0    3   -2    1   -4
## [106]   -1   -6   -3   -8   -5  -10   -7  -12   -9  -14  -11  -16  -13  -18  -15
## [121]  -20  -17  -22  -19  -24  -21  -26  -23  -28  -25  -30  -27  -32  -29  -34
## [136]  -31  -36  -33  -38  -35  -40  -37  -42  -39  -44  -41  -46  -43  -48  -45
## [151]  -50  -47  -52  -49  -54  -51  -56  -53  -58  -55  -60  -57  -62  -59  -64
## [166]  -61  -66  -63  -68  -65  -70  -67  -72  -69  -74  -71  -76  -73  -78  -75
## [181]  -80  -77  -82  -79  -84  -81  -86  -83  -88  -85  -90  -87  -92  -89  -94
## [196]  -91  -96  -93  -98  -95 -100

 

📝Ejercicio 6: diseña el bucle del ejercicio 4 parando cuando no nos quede dinero.

  • Solución:
dinero <- 100 # dinero inicial

# Bucle while
while (dinero > 0) {
  
  dinero <- ifelse(dinero %% 2 == 0, dinero + 3, dinero - 5)
  
}
dinero
## [1] 0

Funciones

(haz click en las flechas para ver soluciones)

Ejercicio 1: modifica el código inferior para definir una función llamada funcion_suma, de forma que dados dos elementos, devuelve su suma.

# Definimos función
nombre <- function(x, y) {
  
  # Sumamos
  suma <- # código a ejecutar
  
  # ¿Qué devolvemos?
  return()
}

# Aplicamos la función
suma(3, 7)

  • Solución:
# Definimos función
funcion_suma <- function(x, y) {
  
  # Sumamos
  suma <- x + y
  
  # Devolvemos la salida
  return(suma)
}

# Aplicamos la función
funcion_suma(3, 7)
## [1] 10

&nsbp;

Ejercicio 2: modifica el código inferior para definir una función llamada funcion_producto, de forma que dados dos elementos, devuelve su producto.

# Definimos función
nombre <- function(x, y) {
  
  # Multiplicamos
  producto <- # código de la multiplicación
  
  # ¿Qué devolvemos?
  return()
}

# Aplicamos la función
producto(3, -7)

  • Solución:
# Definimos función
funcion_producto <- function(x, y) {
  
  # Multiplicamos
  producto <- x * y
  
  # Devolvemos la salida
  return(producto)
}

# Aplicamos la función
funcion_producto(3, -7)
## [1] -21

 

Ejercicio 3: modifica el código inferior para definir una función llamada funcion_producto, de forma que dados dos elementos, devuelve su producto, pero que por defecto calcule el cuadrado (es decir, por defecto un solo argumento, y el resultado sea el número por sí mismo)

# Definimos función
nombre <- function(x, y) {
  
  # Multiplicamos
  producto <- # código de la multiplicación
  
  # ¿Qué devolvemos?
  return()
}

# Aplicamos la función solo con un argumento
producto(3)

# Aplicamos la función con dos argumentos
producto(3, -7)

  • Solución:
# Definimos función
funcion_producto <- function(x, y = x) {
  
  # Multiplicamos
  producto <- x * y
  
  # Devolvemos la salida
  return(producto)
}

# Aplicamos la función
funcion_producto(3) # por defecto x = 3, y = 3
## [1] 9
funcion_producto(3, -7)
## [1] -21

 

Ejercicio 4: define una función llamada igualdad_nombres que, dados dos nombres persona_1 e persona_2, nos diga si son iguales o no. Hazlo considerando importantes las mayúsculas, y sin que importen las mayúsculas. Recuerda que con toupper() podemos pasar todo un texto a mayúscula.

  • Solución:
# Distinguiendo mayúsculas
igualdad_nombres <- function(persona_1, persona_2) {
  
  return(persona_1 == persona_2)
}
igualdad_nombres("Javi", "javi")
## [1] FALSE
igualdad_nombres("Javi", "Lucía")
## [1] FALSE
# Sin importar mayúsculas
igualdad_nombres <- function(persona_1, persona_2) {
  
  return(toupper(persona_1) == toupper(persona_2))
}
igualdad_nombres("Javi", "javi")
## [1] TRUE
igualdad_nombres("Javi", "Lucía")
## [1] FALSE

 

Ejercicio 5: define una función llamada pares que, dados dos números x e y, nos diga si la suma de ambos es par o no.

Recuerda que con %% podemos obtener el resto de un número al dividir entre 2.

2 %% 2 # par, resto 0
## [1] 0
3 %% 2 # impar, resto 1
## [1] 1

  • Solución:
# Definimos función
pares <- function(x, y) {
  
  # Sumamos
  suma <- x + y
  
  # Comprobamos si es par
  par <- suma %% 2 == 0
  
  # Devolvemos la salida
  return(par)
}

# Aplicamos la función
pares(1, 3) # suma 4 (par)
## [1] TRUE
pares(2, 7) # suma 9 (impar)
## [1] FALSE

 

 

Ejercicio 6: define una función llamada pasar_a_celsius que, dada una temperatura \(x\) en Fahrenheit, la convierta a grados Celsius (\(ºC = (ºF - 32) * \frac{5}{9}\)). Aplica la función a la columna Temp del conjunto airquality, e incorpórala al fichero en una nueva columna Temp_Celsius.

  • Solución:
# Definimos función
pasar_a_celsius <- function(x) {
  
  # Temperatura en Celsius
  x_celsius <- (x - 32) * (5 / 9)
  
  # Devolvemos la salida
  return(x_celsius)
}

# Aplicamos la función
pasar_a_celsius(0)
## [1] -17.77778
pasar_a_celsius(80)
## [1] 26.66667
# Aplicamos
data.frame(airquality,
           "Temp_Celsius" = pasar_a_celsius(airquality$Temp))
##     Ozone Solar.R Wind Temp Month Day Temp_Celsius
## 1      41     190  7.4   67     5   1     19.44444
## 2      36     118  8.0   72     5   2     22.22222
## 3      12     149 12.6   74     5   3     23.33333
## 4      18     313 11.5   62     5   4     16.66667
## 5      NA      NA 14.3   56     5   5     13.33333
## 6      28      NA 14.9   66     5   6     18.88889
## 7      23     299  8.6   65     5   7     18.33333
## 8      19      99 13.8   59     5   8     15.00000
## 9       8      19 20.1   61     5   9     16.11111
## 10     NA     194  8.6   69     5  10     20.55556
## 11      7      NA  6.9   74     5  11     23.33333
## 12     16     256  9.7   69     5  12     20.55556
## 13     11     290  9.2   66     5  13     18.88889
## 14     14     274 10.9   68     5  14     20.00000
## 15     18      65 13.2   58     5  15     14.44444
## 16     14     334 11.5   64     5  16     17.77778
## 17     34     307 12.0   66     5  17     18.88889
## 18      6      78 18.4   57     5  18     13.88889
## 19     30     322 11.5   68     5  19     20.00000
## 20     11      44  9.7   62     5  20     16.66667
## 21      1       8  9.7   59     5  21     15.00000
## 22     11     320 16.6   73     5  22     22.77778
## 23      4      25  9.7   61     5  23     16.11111
## 24     32      92 12.0   61     5  24     16.11111
## 25     NA      66 16.6   57     5  25     13.88889
## 26     NA     266 14.9   58     5  26     14.44444
## 27     NA      NA  8.0   57     5  27     13.88889
## 28     23      13 12.0   67     5  28     19.44444
## 29     45     252 14.9   81     5  29     27.22222
## 30    115     223  5.7   79     5  30     26.11111
## 31     37     279  7.4   76     5  31     24.44444
## 32     NA     286  8.6   78     6   1     25.55556
## 33     NA     287  9.7   74     6   2     23.33333
## 34     NA     242 16.1   67     6   3     19.44444
## 35     NA     186  9.2   84     6   4     28.88889
## 36     NA     220  8.6   85     6   5     29.44444
## 37     NA     264 14.3   79     6   6     26.11111
## 38     29     127  9.7   82     6   7     27.77778
## 39     NA     273  6.9   87     6   8     30.55556
## 40     71     291 13.8   90     6   9     32.22222
## 41     39     323 11.5   87     6  10     30.55556
## 42     NA     259 10.9   93     6  11     33.88889
## 43     NA     250  9.2   92     6  12     33.33333
## 44     23     148  8.0   82     6  13     27.77778
## 45     NA     332 13.8   80     6  14     26.66667
## 46     NA     322 11.5   79     6  15     26.11111
## 47     21     191 14.9   77     6  16     25.00000
## 48     37     284 20.7   72     6  17     22.22222
## 49     20      37  9.2   65     6  18     18.33333
## 50     12     120 11.5   73     6  19     22.77778
## 51     13     137 10.3   76     6  20     24.44444
## 52     NA     150  6.3   77     6  21     25.00000
## 53     NA      59  1.7   76     6  22     24.44444
## 54     NA      91  4.6   76     6  23     24.44444
## 55     NA     250  6.3   76     6  24     24.44444
## 56     NA     135  8.0   75     6  25     23.88889
## 57     NA     127  8.0   78     6  26     25.55556
## 58     NA      47 10.3   73     6  27     22.77778
## 59     NA      98 11.5   80     6  28     26.66667
## 60     NA      31 14.9   77     6  29     25.00000
## 61     NA     138  8.0   83     6  30     28.33333
## 62    135     269  4.1   84     7   1     28.88889
## 63     49     248  9.2   85     7   2     29.44444
## 64     32     236  9.2   81     7   3     27.22222
## 65     NA     101 10.9   84     7   4     28.88889
## 66     64     175  4.6   83     7   5     28.33333
## 67     40     314 10.9   83     7   6     28.33333
## 68     77     276  5.1   88     7   7     31.11111
## 69     97     267  6.3   92     7   8     33.33333
## 70     97     272  5.7   92     7   9     33.33333
## 71     85     175  7.4   89     7  10     31.66667
## 72     NA     139  8.6   82     7  11     27.77778
## 73     10     264 14.3   73     7  12     22.77778
## 74     27     175 14.9   81     7  13     27.22222
## 75     NA     291 14.9   91     7  14     32.77778
## 76      7      48 14.3   80     7  15     26.66667
## 77     48     260  6.9   81     7  16     27.22222
## 78     35     274 10.3   82     7  17     27.77778
## 79     61     285  6.3   84     7  18     28.88889
## 80     79     187  5.1   87     7  19     30.55556
## 81     63     220 11.5   85     7  20     29.44444
## 82     16       7  6.9   74     7  21     23.33333
## 83     NA     258  9.7   81     7  22     27.22222
## 84     NA     295 11.5   82     7  23     27.77778
## 85     80     294  8.6   86     7  24     30.00000
## 86    108     223  8.0   85     7  25     29.44444
## 87     20      81  8.6   82     7  26     27.77778
## 88     52      82 12.0   86     7  27     30.00000
## 89     82     213  7.4   88     7  28     31.11111
## 90     50     275  7.4   86     7  29     30.00000
## 91     64     253  7.4   83     7  30     28.33333
## 92     59     254  9.2   81     7  31     27.22222
## 93     39      83  6.9   81     8   1     27.22222
## 94      9      24 13.8   81     8   2     27.22222
## 95     16      77  7.4   82     8   3     27.77778
## 96     78      NA  6.9   86     8   4     30.00000
## 97     35      NA  7.4   85     8   5     29.44444
## 98     66      NA  4.6   87     8   6     30.55556
## 99    122     255  4.0   89     8   7     31.66667
## 100    89     229 10.3   90     8   8     32.22222
## 101   110     207  8.0   90     8   9     32.22222
## 102    NA     222  8.6   92     8  10     33.33333
## 103    NA     137 11.5   86     8  11     30.00000
## 104    44     192 11.5   86     8  12     30.00000
## 105    28     273 11.5   82     8  13     27.77778
## 106    65     157  9.7   80     8  14     26.66667
## 107    NA      64 11.5   79     8  15     26.11111
## 108    22      71 10.3   77     8  16     25.00000
## 109    59      51  6.3   79     8  17     26.11111
## 110    23     115  7.4   76     8  18     24.44444
## 111    31     244 10.9   78     8  19     25.55556
## 112    44     190 10.3   78     8  20     25.55556
## 113    21     259 15.5   77     8  21     25.00000
## 114     9      36 14.3   72     8  22     22.22222
## 115    NA     255 12.6   75     8  23     23.88889
## 116    45     212  9.7   79     8  24     26.11111
## 117   168     238  3.4   81     8  25     27.22222
## 118    73     215  8.0   86     8  26     30.00000
## 119    NA     153  5.7   88     8  27     31.11111
## 120    76     203  9.7   97     8  28     36.11111
## 121   118     225  2.3   94     8  29     34.44444
## 122    84     237  6.3   96     8  30     35.55556
## 123    85     188  6.3   94     8  31     34.44444
## 124    96     167  6.9   91     9   1     32.77778
## 125    78     197  5.1   92     9   2     33.33333
## 126    73     183  2.8   93     9   3     33.88889
## 127    91     189  4.6   93     9   4     33.88889
## 128    47      95  7.4   87     9   5     30.55556
## 129    32      92 15.5   84     9   6     28.88889
## 130    20     252 10.9   80     9   7     26.66667
## 131    23     220 10.3   78     9   8     25.55556
## 132    21     230 10.9   75     9   9     23.88889
## 133    24     259  9.7   73     9  10     22.77778
## 134    44     236 14.9   81     9  11     27.22222
## 135    21     259 15.5   76     9  12     24.44444
## 136    28     238  6.3   77     9  13     25.00000
## 137     9      24 10.9   71     9  14     21.66667
## 138    13     112 11.5   71     9  15     21.66667
## 139    46     237  6.9   78     9  16     25.55556
## 140    18     224 13.8   67     9  17     19.44444
## 141    13      27 10.3   76     9  18     24.44444
## 142    24     238 10.3   68     9  19     20.00000
## 143    16     201  8.0   82     9  20     27.77778
## 144    13     238 12.6   64     9  21     17.77778
## 145    23      14  9.2   71     9  22     21.66667
## 146    36     139 10.3   81     9  23     27.22222
## 147     7      49 10.3   69     9  24     20.55556
## 148    14      20 16.6   63     9  25     17.22222
## 149    30     193  6.9   70     9  26     21.11111
## 150    NA     145 13.2   77     9  27     25.00000
## 151    14     191 14.3   75     9  28     23.88889
## 152    18     131  8.0   76     9  29     24.44444
## 153    20     223 11.5   68     9  30     20.00000

 

Listas

Ejercicio 1: define una lista de 4 elementos de tipos distintos y accede al segundo de ellos (yo incluiré uno que sea un data.frame para que veas que en una lista cabe de todo).

  • Solución:
# Ejemplo: lista con texto, numérico, lógico y un data.frame
lista_ejemplo <- list("nombre" = "Javier", "cp" = 28019,
                      "soltero" = TRUE,
                      "notas" = data.frame("mates" = c(7.5, 8, 9),
                                           "lengua" = c(10, 5, 6)))
lista_ejemplo
## $nombre
## [1] "Javier"
## 
## $cp
## [1] 28019
## 
## $soltero
## [1] TRUE
## 
## $notas
##   mates lengua
## 1   7.5     10
## 2   8.0      5
## 3   9.0      6
# Longitud
length(lista_ejemplo)
## [1] 4
# Accedemos al elemento dos
lista_ejemplo[[2]]
## [1] 28019

 

Ejercicio 2: accede a los elementos que ocupan los lugares 1 y 4 de la lista definida anteriormente.

  • Solución:
# Accedemos al 1 y al 4
lista_ejemplo[c(1, 4)]
## $nombre
## [1] "Javier"
## 
## $notas
##   mates lengua
## 1   7.5     10
## 2   8.0      5
## 3   9.0      6

Otra opción es acceder con los nombres

# Accedemos al 1 y al 4
lista_ejemplo$nombre
## [1] "Javier"
lista_ejemplo$notas
##   mates lengua
## 1   7.5     10
## 2   8.0      5
## 3   9.0      6
lista_ejemplo[c("nombre", "notas")]
## $nombre
## [1] "Javier"
## 
## $notas
##   mates lengua
## 1   7.5     10
## 2   8.0      5
## 3   9.0      6

 

Ejercicio 3: define una lista de 4 elementos que contenga, en una sola variable, tu nombre, apellido, edad y si estás soltero/a.

  • Solución:
library(lubridate)
# Creamos lista: con lubridate calculamos la diferencia de años desde la fecha de nuestro nacimiento hasta hoy (sea cuando sea hoy)
lista_personal <- list("nombre" = "Javier",
                       "apellidos" = "Álvarez Liébana",
                       "edad" = 32,
                       "soltero" = TRUE)
lista_personal
## $nombre
## [1] "Javier"
## 
## $apellidos
## [1] "Álvarez Liébana"
## 
## $edad
## [1] 32
## 
## $soltero
## [1] TRUE

Tibble

(haz click en las flechas para ver soluciones)

📝Ejercicio 1: ¿es el conjunto de datos airquality (del paquete {datasets}) de tipo tibble?

  • Solución:

Recuerda que podemos cargar elementos de un paquete (en este caso {datasets}) cargando library(datasets) y luego el elemento, o bien datasets::airquality (prefijo::nombre).

La respuesta: NO. Tienes muchas formas de comprobarlo si imprimes el conjunto por defecto.

library(datasets)
airquality
##     Ozone Solar.R Wind Temp Month Day
## 1      41     190  7.4   67     5   1
## 2      36     118  8.0   72     5   2
## 3      12     149 12.6   74     5   3
## 4      18     313 11.5   62     5   4
## 5      NA      NA 14.3   56     5   5
## 6      28      NA 14.9   66     5   6
## 7      23     299  8.6   65     5   7
## 8      19      99 13.8   59     5   8
## 9       8      19 20.1   61     5   9
## 10     NA     194  8.6   69     5  10
## 11      7      NA  6.9   74     5  11
## 12     16     256  9.7   69     5  12
## 13     11     290  9.2   66     5  13
## 14     14     274 10.9   68     5  14
## 15     18      65 13.2   58     5  15
## 16     14     334 11.5   64     5  16
## 17     34     307 12.0   66     5  17
## 18      6      78 18.4   57     5  18
## 19     30     322 11.5   68     5  19
## 20     11      44  9.7   62     5  20
## 21      1       8  9.7   59     5  21
## 22     11     320 16.6   73     5  22
## 23      4      25  9.7   61     5  23
## 24     32      92 12.0   61     5  24
## 25     NA      66 16.6   57     5  25
## 26     NA     266 14.9   58     5  26
## 27     NA      NA  8.0   57     5  27
## 28     23      13 12.0   67     5  28
## 29     45     252 14.9   81     5  29
## 30    115     223  5.7   79     5  30
## 31     37     279  7.4   76     5  31
## 32     NA     286  8.6   78     6   1
## 33     NA     287  9.7   74     6   2
## 34     NA     242 16.1   67     6   3
## 35     NA     186  9.2   84     6   4
## 36     NA     220  8.6   85     6   5
## 37     NA     264 14.3   79     6   6
## 38     29     127  9.7   82     6   7
## 39     NA     273  6.9   87     6   8
## 40     71     291 13.8   90     6   9
## 41     39     323 11.5   87     6  10
## 42     NA     259 10.9   93     6  11
## 43     NA     250  9.2   92     6  12
## 44     23     148  8.0   82     6  13
## 45     NA     332 13.8   80     6  14
## 46     NA     322 11.5   79     6  15
## 47     21     191 14.9   77     6  16
## 48     37     284 20.7   72     6  17
## 49     20      37  9.2   65     6  18
## 50     12     120 11.5   73     6  19
## 51     13     137 10.3   76     6  20
## 52     NA     150  6.3   77     6  21
## 53     NA      59  1.7   76     6  22
## 54     NA      91  4.6   76     6  23
## 55     NA     250  6.3   76     6  24
## 56     NA     135  8.0   75     6  25
## 57     NA     127  8.0   78     6  26
## 58     NA      47 10.3   73     6  27
## 59     NA      98 11.5   80     6  28
## 60     NA      31 14.9   77     6  29
## 61     NA     138  8.0   83     6  30
## 62    135     269  4.1   84     7   1
## 63     49     248  9.2   85     7   2
## 64     32     236  9.2   81     7   3
## 65     NA     101 10.9   84     7   4
## 66     64     175  4.6   83     7   5
## 67     40     314 10.9   83     7   6
## 68     77     276  5.1   88     7   7
## 69     97     267  6.3   92     7   8
## 70     97     272  5.7   92     7   9
## 71     85     175  7.4   89     7  10
## 72     NA     139  8.6   82     7  11
## 73     10     264 14.3   73     7  12
## 74     27     175 14.9   81     7  13
## 75     NA     291 14.9   91     7  14
## 76      7      48 14.3   80     7  15
## 77     48     260  6.9   81     7  16
## 78     35     274 10.3   82     7  17
## 79     61     285  6.3   84     7  18
## 80     79     187  5.1   87     7  19
## 81     63     220 11.5   85     7  20
## 82     16       7  6.9   74     7  21
## 83     NA     258  9.7   81     7  22
## 84     NA     295 11.5   82     7  23
## 85     80     294  8.6   86     7  24
## 86    108     223  8.0   85     7  25
## 87     20      81  8.6   82     7  26
## 88     52      82 12.0   86     7  27
## 89     82     213  7.4   88     7  28
## 90     50     275  7.4   86     7  29
## 91     64     253  7.4   83     7  30
## 92     59     254  9.2   81     7  31
## 93     39      83  6.9   81     8   1
## 94      9      24 13.8   81     8   2
## 95     16      77  7.4   82     8   3
## 96     78      NA  6.9   86     8   4
## 97     35      NA  7.4   85     8   5
## 98     66      NA  4.6   87     8   6
## 99    122     255  4.0   89     8   7
## 100    89     229 10.3   90     8   8
## 101   110     207  8.0   90     8   9
## 102    NA     222  8.6   92     8  10
## 103    NA     137 11.5   86     8  11
## 104    44     192 11.5   86     8  12
## 105    28     273 11.5   82     8  13
## 106    65     157  9.7   80     8  14
## 107    NA      64 11.5   79     8  15
## 108    22      71 10.3   77     8  16
## 109    59      51  6.3   79     8  17
## 110    23     115  7.4   76     8  18
## 111    31     244 10.9   78     8  19
## 112    44     190 10.3   78     8  20
## 113    21     259 15.5   77     8  21
## 114     9      36 14.3   72     8  22
## 115    NA     255 12.6   75     8  23
## 116    45     212  9.7   79     8  24
## 117   168     238  3.4   81     8  25
## 118    73     215  8.0   86     8  26
## 119    NA     153  5.7   88     8  27
## 120    76     203  9.7   97     8  28
## 121   118     225  2.3   94     8  29
## 122    84     237  6.3   96     8  30
## 123    85     188  6.3   94     8  31
## 124    96     167  6.9   91     9   1
## 125    78     197  5.1   92     9   2
## 126    73     183  2.8   93     9   3
## 127    91     189  4.6   93     9   4
## 128    47      95  7.4   87     9   5
## 129    32      92 15.5   84     9   6
## 130    20     252 10.9   80     9   7
## 131    23     220 10.3   78     9   8
## 132    21     230 10.9   75     9   9
## 133    24     259  9.7   73     9  10
## 134    44     236 14.9   81     9  11
## 135    21     259 15.5   76     9  12
## 136    28     238  6.3   77     9  13
## 137     9      24 10.9   71     9  14
## 138    13     112 11.5   71     9  15
## 139    46     237  6.9   78     9  16
## 140    18     224 13.8   67     9  17
## 141    13      27 10.3   76     9  18
## 142    24     238 10.3   68     9  19
## 143    16     201  8.0   82     9  20
## 144    13     238 12.6   64     9  21
## 145    23      14  9.2   71     9  22
## 146    36     139 10.3   81     9  23
## 147     7      49 10.3   69     9  24
## 148    14      20 16.6   63     9  25
## 149    30     193  6.9   70     9  26
## 150    NA     145 13.2   77     9  27
## 151    14     191 14.3   75     9  28
## 152    18     131  8.0   76     9  29
## 153    20     223 11.5   68     9  30
class(airquality)
## [1] "data.frame"
  • Imprime por defecto todas las filas (tiene 153 filas, debería imprimir solo 10 si fuese un tibble, para no saturar consola).
  • No especifica al imprimir que es de tipo tibble.
  • No especifica al imprimir el tipo de dato de las columnas.
  • Imprime el nombre de las filas (el nombre de los modelos) como si fuera una variable (¡que no existe!).

 

📝Ejercicio 2: convierte el conjunto airquality de data.frame a tibble.

  • Solución:

Así debería de salir si fuera tibble.

library(dplyr)
airquality_tb <- as_tibble(airquality)
airquality_tb
## # A tibble: 153 × 6
##    Ozone Solar.R  Wind  Temp Month   Day
##    <int>   <int> <dbl> <int> <int> <int>
##  1    41     190   7.4    67     5     1
##  2    36     118   8      72     5     2
##  3    12     149  12.6    74     5     3
##  4    18     313  11.5    62     5     4
##  5    NA      NA  14.3    56     5     5
##  6    28      NA  14.9    66     5     6
##  7    23     299   8.6    65     5     7
##  8    19      99  13.8    59     5     8
##  9     8      19  20.1    61     5     9
## 10    NA     194   8.6    69     5    10
## # … with 143 more rows
class(airquality_tb)
## [1] "tbl_df"     "tbl"        "data.frame"

 

📝Ejercicio 3: define un tibble con tres variables numéricas a, b, c, tal que la tercera sea el producto de las dos primeras c = a * b. Inténtalo hacer con un data.frame

  • Solución:

Un ejemplo:

tibble("a" = 1:7, "b" = 11:17, "c" = a * b)
## # A tibble: 7 × 3
##       a     b     c
##   <int> <int> <int>
## 1     1    11    11
## 2     2    12    24
## 3     3    13    39
## 4     4    14    56
## 5     5    15    75
## 6     6    16    96
## 7     7    17   119

Si lo intentamos con un data.frame, intentará buscar una variable real que tengamos guardada que se llame a y b, sin encontrarlas.

data.frame("a" = 1:7, "b" = 11:17, "c" = a * b)
##   a  b   c
## 1 1 11 -35
## 2 2 12 -35
## 3 3 13 -35
## 4 4 14 -35
## 5 5 15 -35
## 6 6 16 -35
## 7 7 17 -35

 

📝Ejercicio 4: define un tibble con tres variables de nombres variable, 2, tercera :), e intenta acceder a ellas.

  • Solución:

Las variables solo con caracteres del alfabeto se podrán acceder sin necesidad de comillas.

# Definimos el tibble
datos_tb <- tibble("variable" = 1:7, "tercera falsa :)" = 0,
                   "2" = 11:17)

# Accedemos a sus columnas
datos_tb$variable
## [1] 1 2 3 4 5 6 7
datos_tb$`tercera falsa :)`
## [1] 0 0 0 0 0 0 0
datos_tb$`2`
## [1] 11 12 13 14 15 16 17

También se puede acceder por el orden que ocupan:

datos_tb[1]
## # A tibble: 7 × 1
##   variable
##      <int>
## 1        1
## 2        2
## 3        3
## 4        4
## 5        5
## 6        6
## 7        7
datos_tb[2]
## # A tibble: 7 × 1
##   `tercera falsa :)`
##                <dbl>
## 1                  0
## 2                  0
## 3                  0
## 4                  0
## 5                  0
## 6                  0
## 7                  0
datos_tb[3]
## # A tibble: 7 × 1
##     `2`
##   <int>
## 1    11
## 2    12
## 3    13
## 4    14
## 5    15
## 6    16
## 7    17

Y también por el nombre entre corchetes (doble corchete extrae la variable fuera del tibble, corchete simple en formato tibble):

datos_tb["variable"]
## # A tibble: 7 × 1
##   variable
##      <int>
## 1        1
## 2        2
## 3        3
## 4        4
## 5        5
## 6        6
## 7        7
datos_tb[["variable"]]
## [1] 1 2 3 4 5 6 7
datos_tb["tercera falsa :)"]
## # A tibble: 7 × 1
##   `tercera falsa :)`
##                <dbl>
## 1                  0
## 2                  0
## 3                  0
## 4                  0
## 5                  0
## 6                  0
## 7                  0
datos_tb["2"]
## # A tibble: 7 × 1
##     `2`
##   <int>
## 1    11
## 2    12
## 3    13
## 4    14
## 5    15
## 6    16
## 7    17

 

📝Ejercicio 5: obten de los paquetes dplyr y gapminder los conjuntos de datos tibble starwars y gapminder. Comprueba el número de variables, de registros e imprime los datos

  • Solución:
# starwars
library(dplyr)
starwars
## # A tibble: 87 × 14
##    name    height  mass hair_color  skin_color eye_color birth_year sex   gender
##    <chr>    <int> <dbl> <chr>       <chr>      <chr>          <dbl> <chr> <chr> 
##  1 Luke S…    172    77 blond       fair       blue            19   male  mascu…
##  2 C-3PO      167    75 <NA>        gold       yellow         112   none  mascu…
##  3 R2-D2       96    32 <NA>        white, bl… red             33   none  mascu…
##  4 Darth …    202   136 none        white      yellow          41.9 male  mascu…
##  5 Leia O…    150    49 brown       light      brown           19   fema… femin…
##  6 Owen L…    178   120 brown, grey light      blue            52   male  mascu…
##  7 Beru W…    165    75 brown       light      blue            47   fema… femin…
##  8 R5-D4       97    32 <NA>        white, red red             NA   none  mascu…
##  9 Biggs …    183    84 black       light      brown           24   male  mascu…
## 10 Obi-Wa…    182    77 auburn, wh… fair       blue-gray       57   male  mascu…
## # … with 77 more rows, and 5 more variables: homeworld <chr>, species <chr>,
## #   films <list>, vehicles <list>, starships <list>
glimpse(starwars) # resumen de columnas
## Rows: 87
## Columns: 14
## $ name       <chr> "Luke Skywalker", "C-3PO", "R2-D2", "Darth Vader", "Leia Or…
## $ height     <int> 172, 167, 96, 202, 150, 178, 165, 97, 183, 182, 188, 180, 2…
## $ mass       <dbl> 77.0, 75.0, 32.0, 136.0, 49.0, 120.0, 75.0, 32.0, 84.0, 77.…
## $ hair_color <chr> "blond", NA, NA, "none", "brown", "brown, grey", "brown", N…
## $ skin_color <chr> "fair", "gold", "white, blue", "white", "light", "light", "…
## $ eye_color  <chr> "blue", "yellow", "red", "yellow", "brown", "blue", "blue",…
## $ birth_year <dbl> 19.0, 112.0, 33.0, 41.9, 19.0, 52.0, 47.0, NA, 24.0, 57.0, …
## $ sex        <chr> "male", "none", "none", "male", "female", "male", "female",…
## $ gender     <chr> "masculine", "masculine", "masculine", "masculine", "femini…
## $ homeworld  <chr> "Tatooine", "Tatooine", "Naboo", "Tatooine", "Alderaan", "T…
## $ species    <chr> "Human", "Droid", "Droid", "Human", "Human", "Human", "Huma…
## $ films      <list> <"The Empire Strikes Back", "Revenge of the Sith", "Return…
## $ vehicles   <list> <"Snowspeeder", "Imperial Speeder Bike">, <>, <>, <>, "Imp…
## $ starships  <list> <"X-wing", "Imperial shuttle">, <>, <>, "TIE Advanced x1",…
dim(starwars) # dimensiones
## [1] 87 14
# gapminder
library(gapminder)
gapminder
## # A tibble: 1,704 × 6
##    country     continent  year lifeExp      pop gdpPercap
##    <fct>       <fct>     <int>   <dbl>    <int>     <dbl>
##  1 Afghanistan Asia       1952    28.8  8425333      779.
##  2 Afghanistan Asia       1957    30.3  9240934      821.
##  3 Afghanistan Asia       1962    32.0 10267083      853.
##  4 Afghanistan Asia       1967    34.0 11537966      836.
##  5 Afghanistan Asia       1972    36.1 13079460      740.
##  6 Afghanistan Asia       1977    38.4 14880372      786.
##  7 Afghanistan Asia       1982    39.9 12881816      978.
##  8 Afghanistan Asia       1987    40.8 13867957      852.
##  9 Afghanistan Asia       1992    41.7 16317921      649.
## 10 Afghanistan Asia       1997    41.8 22227415      635.
## # … with 1,694 more rows
glimpse(gapminder) # resumen de columnas
## Rows: 1,704
## Columns: 6
## $ country   <fct> "Afghanistan", "Afghanistan", "Afghanistan", "Afghanistan", …
## $ continent <fct> Asia, Asia, Asia, Asia, Asia, Asia, Asia, Asia, Asia, Asia, …
## $ year      <int> 1952, 1957, 1962, 1967, 1972, 1977, 1982, 1987, 1992, 1997, …
## $ lifeExp   <dbl> 28.801, 30.332, 31.997, 34.020, 36.088, 38.438, 39.854, 40.8…
## $ pop       <int> 8425333, 9240934, 10267083, 11537966, 13079460, 14880372, 12…
## $ gdpPercap <dbl> 779.4453, 820.8530, 853.1007, 836.1971, 739.9811, 786.1134, …
dim(gapminder) # dimensiones
## [1] 1704    6

 

Tidy data

(haz click en las flechas para ver soluciones)

📝Ejercicio 1: convierte en tidy data el siguiente data.frame.

library(tibble)
library(tidyr)
tabla_tb <- tibble("trimestre" = c("T1", "T2", "T3"),
                   "2020" = c(10, 12, 7.5),
                   "2021" = c(8, 0, 9))
  • Solución:

El problema es que las dos columnas con nombres de año son en realidad valores que deberían pasar a ser variables, así que deberíamos disminuir aplicar pivot_longer()

# Aplicamos pivot_longer
tabla_tb %>% pivot_longer(cols = c("2020", "2021"),
                          names_to = "año", values_to = "valores")
## # A tibble: 6 × 3
##   trimestre año   valores
##   <chr>     <chr>   <dbl>
## 1 T1        2020     10  
## 2 T1        2021      8  
## 3 T2        2020     12  
## 4 T2        2021      0  
## 5 T3        2020      7.5
## 6 T3        2021      9

 

📝Ejercicio 2: convierte en tidy data el siguiente data.frame.

tabla_tb <- tibble("año" = c(2019, 2019, 2020, 2020, 2021, 2021),
                   "variable" = c("A", "B", "A", "B", "A", "B"),
                   "valor" = c(10, 9383, 7.58, 10839, 9, 32949))
  • Solución:

El problema es que las filas que comparten año son el mismo registro (pero con dos características que tenemos divididas en dos filas), así que deberíamos disminuir aplicar pivot_wider()

# Aplicamos pivot_wider
tabla_tb %>% pivot_wider(names_from = "variable", values_from = "valor")
## # A tibble: 3 × 3
##     año     A     B
##   <dbl> <dbl> <dbl>
## 1  2019 10     9383
## 2  2020  7.58 10839
## 3  2021  9    32949

 

📝Ejercicio 3: convierte en tidy data la tabla table5 del paquete tidyr.

  • Solución:

Primero uniremos el siglo y las dos últimas cifras del año para obtener el año completo (guardado en año)

table5 %>%
  unite(año, century, year, sep = "")
## # A tibble: 6 × 3
##   country     año   rate             
##   <chr>       <chr> <chr>            
## 1 Afghanistan 1999  745/19987071     
## 2 Afghanistan 2000  2666/20595360    
## 3 Brazil      1999  37737/172006362  
## 4 Brazil      2000  80488/174504898  
## 5 China       1999  212258/1272915272
## 6 China       2000  213766/1280428583

Tras ello deberemos separar el valor del ratio en denominador y numerador (ya que ahora hay dos valores en una celda), y convertiremos el tipo de dato en la salida para que sea número.

table5 %>%
  unite(año, century, year, sep = "") %>%
  separate(rate, c("numerador", "denominador"), convert = TRUE)
## # A tibble: 6 × 4
##   country     año   numerador denominador
##   <chr>       <chr>     <int>       <int>
## 1 Afghanistan 1999        745    19987071
## 2 Afghanistan 2000       2666    20595360
## 3 Brazil      1999      37737   172006362
## 4 Brazil      2000      80488   174504898
## 5 China       1999     212258  1272915272
## 6 China       2000     213766  1280428583

Intro a tidyverse

(haz click en las flechas para ver soluciones)

📝Ejercicio 1: carga el conjunto de datos starwars y determina el tipo de variables, el númwero de filas y el número de columnas.

  • Solución:
library(tidyverse)

# carga
starwars
## # A tibble: 87 × 14
##    name    height  mass hair_color  skin_color eye_color birth_year sex   gender
##    <chr>    <int> <dbl> <chr>       <chr>      <chr>          <dbl> <chr> <chr> 
##  1 Luke S…    172    77 blond       fair       blue            19   male  mascu…
##  2 C-3PO      167    75 <NA>        gold       yellow         112   none  mascu…
##  3 R2-D2       96    32 <NA>        white, bl… red             33   none  mascu…
##  4 Darth …    202   136 none        white      yellow          41.9 male  mascu…
##  5 Leia O…    150    49 brown       light      brown           19   fema… femin…
##  6 Owen L…    178   120 brown, grey light      blue            52   male  mascu…
##  7 Beru W…    165    75 brown       light      blue            47   fema… femin…
##  8 R5-D4       97    32 <NA>        white, red red             NA   none  mascu…
##  9 Biggs …    183    84 black       light      brown           24   male  mascu…
## 10 Obi-Wa…    182    77 auburn, wh… fair       blue-gray       57   male  mascu…
## # … with 77 more rows, and 5 more variables: homeworld <chr>, species <chr>,
## #   films <list>, vehicles <list>, starships <list>
# dimensiones
nrow(starwars)
## [1] 87
ncol(starwars)
## [1] 14
dim(starwars)
## [1] 87 14
# Tipos de variables
glimpse(starwars)
## Rows: 87
## Columns: 14
## $ name       <chr> "Luke Skywalker", "C-3PO", "R2-D2", "Darth Vader", "Leia Or…
## $ height     <int> 172, 167, 96, 202, 150, 178, 165, 97, 183, 182, 188, 180, 2…
## $ mass       <dbl> 77.0, 75.0, 32.0, 136.0, 49.0, 120.0, 75.0, 32.0, 84.0, 77.…
## $ hair_color <chr> "blond", NA, NA, "none", "brown", "brown, grey", "brown", N…
## $ skin_color <chr> "fair", "gold", "white, blue", "white", "light", "light", "…
## $ eye_color  <chr> "blue", "yellow", "red", "yellow", "brown", "blue", "blue",…
## $ birth_year <dbl> 19.0, 112.0, 33.0, 41.9, 19.0, 52.0, 47.0, NA, 24.0, 57.0, …
## $ sex        <chr> "male", "none", "none", "male", "female", "male", "female",…
## $ gender     <chr> "masculine", "masculine", "masculine", "masculine", "femini…
## $ homeworld  <chr> "Tatooine", "Tatooine", "Naboo", "Tatooine", "Alderaan", "T…
## $ species    <chr> "Human", "Droid", "Droid", "Human", "Human", "Human", "Huma…
## $ films      <list> <"The Empire Strikes Back", "Revenge of the Sith", "Return…
## $ vehicles   <list> <"Snowspeeder", "Imperial Speeder Bike">, <>, <>, <>, "Imp…
## $ starships  <list> <"X-wing", "Imperial shuttle">, <>, <>, "TIE Advanced x1",…

 

📝Ejercicio 2: del conjunto starwars encuentra todos los personajes cuyo peso esté entre 60kg y 90kg. Imprime todas las columnas del filtro.

  • Solución:
# todas columnas
filtro <-
  starwars %>% filter(between(mass, 60, 90))
print(filtro, width = Inf)
## # A tibble: 32 × 14
##    name               height  mass hair_color    skin_color eye_color birth_year
##    <chr>               <int> <dbl> <chr>         <chr>      <chr>          <dbl>
##  1 Luke Skywalker        172    77 blond         fair       blue            19  
##  2 C-3PO                 167    75 <NA>          gold       yellow         112  
##  3 Beru Whitesun lars    165    75 brown         light      blue            47  
##  4 Biggs Darklighter     183    84 black         light      brown           24  
##  5 Obi-Wan Kenobi        182    77 auburn, white fair       blue-gray       57  
##  6 Anakin Skywalker      188    84 blond         fair       blue            41.9
##  7 Han Solo              180    80 brown         fair       brown           29  
##  8 Greedo                173    74 <NA>          green      black           44  
##  9 Wedge Antilles        170    77 brown         fair       hazel           21  
## 10 Palpatine             170    75 grey          pale       yellow          82  
##    sex    gender    homeworld species films     vehicles  starships
##    <chr>  <chr>     <chr>     <chr>   <list>    <list>    <list>   
##  1 male   masculine Tatooine  Human   <chr [5]> <chr [2]> <chr [2]>
##  2 none   masculine Tatooine  Droid   <chr [6]> <chr [0]> <chr [0]>
##  3 female feminine  Tatooine  Human   <chr [3]> <chr [0]> <chr [0]>
##  4 male   masculine Tatooine  Human   <chr [1]> <chr [0]> <chr [1]>
##  5 male   masculine Stewjon   Human   <chr [6]> <chr [1]> <chr [5]>
##  6 male   masculine Tatooine  Human   <chr [3]> <chr [2]> <chr [3]>
##  7 male   masculine Corellia  Human   <chr [4]> <chr [0]> <chr [2]>
##  8 male   masculine Rodia     Rodian  <chr [1]> <chr [0]> <chr [0]>
##  9 male   masculine Corellia  Human   <chr [3]> <chr [1]> <chr [1]>
## 10 male   masculine Naboo     Human   <chr [5]> <chr [0]> <chr [0]>
## # … with 22 more rows

 

📝Ejercicio 3: añadido al filtro anterior, encuentra todos los personajes que además tengan los ojos que no sean azules.

  • Solución:
# todas columnas
filtro <-
  starwars %>%
  filter(between(mass, 60, 90) & eye_color != "blue")
print(filtro, width = Inf)
## # A tibble: 27 × 14
##    name              height  mass hair_color    skin_color   eye_color
##    <chr>              <int> <dbl> <chr>         <chr>        <chr>    
##  1 C-3PO                167  75   <NA>          gold         yellow   
##  2 Biggs Darklighter    183  84   black         light        brown    
##  3 Obi-Wan Kenobi       182  77   auburn, white fair         blue-gray
##  4 Han Solo             180  80   brown         fair         brown    
##  5 Greedo               173  74   <NA>          green        black    
##  6 Wedge Antilles       170  77   brown         fair         hazel    
##  7 Palpatine            170  75   grey          pale         yellow   
##  8 Boba Fett            183  78.2 black         fair         brown    
##  9 Lando Calrissian     177  79   black         dark         brown    
## 10 Ackbar               180  83   none          brown mottle orange   
##    birth_year sex   gender    homeworld species      films     vehicles 
##         <dbl> <chr> <chr>     <chr>     <chr>        <list>    <list>   
##  1      112   none  masculine Tatooine  Droid        <chr [6]> <chr [0]>
##  2       24   male  masculine Tatooine  Human        <chr [1]> <chr [0]>
##  3       57   male  masculine Stewjon   Human        <chr [6]> <chr [1]>
##  4       29   male  masculine Corellia  Human        <chr [4]> <chr [0]>
##  5       44   male  masculine Rodia     Rodian       <chr [1]> <chr [0]>
##  6       21   male  masculine Corellia  Human        <chr [3]> <chr [1]>
##  7       82   male  masculine Naboo     Human        <chr [5]> <chr [0]>
##  8       31.5 male  masculine Kamino    Human        <chr [3]> <chr [0]>
##  9       31   male  masculine Socorro   Human        <chr [2]> <chr [0]>
## 10       41   male  masculine Mon Cala  Mon Calamari <chr [2]> <chr [0]>
##    starships
##    <list>   
##  1 <chr [0]>
##  2 <chr [1]>
##  3 <chr [5]>
##  4 <chr [2]>
##  5 <chr [0]>
##  6 <chr [1]>
##  7 <chr [0]>
##  8 <chr [1]>
##  9 <chr [1]>
## 10 <chr [0]>
## # … with 17 more rows

 

📝Ejercicio 4: añadido al filtro anterior, encuentra todos los personajes que además tengan menos de 100 años.

  • Solución:
# todas columnas
filtro <-
  starwars %>%
  filter(between(mass, 60, 90) & eye_color != "blue" &
           birth_year < 100)
print(filtro, width = Inf)
## # A tibble: 15 × 14
##    name              height  mass hair_color    skin_color   eye_color
##    <chr>              <int> <dbl> <chr>         <chr>        <chr>    
##  1 Biggs Darklighter    183  84   black         light        brown    
##  2 Obi-Wan Kenobi       182  77   auburn, white fair         blue-gray
##  3 Han Solo             180  80   brown         fair         brown    
##  4 Greedo               173  74   <NA>          green        black    
##  5 Wedge Antilles       170  77   brown         fair         hazel    
##  6 Palpatine            170  75   grey          pale         yellow   
##  7 Boba Fett            183  78.2 black         fair         brown    
##  8 Lando Calrissian     177  79   black         dark         brown    
##  9 Ackbar               180  83   none          brown mottle orange   
## 10 Jar Jar Binks        196  66   none          orange       orange   
## 11 Darth Maul           175  80   none          red          yellow   
## 12 Mace Windu           188  84   none          dark         brown    
## 13 Ki-Adi-Mundi         198  82   white         pale         yellow   
## 14 Plo Koon             188  80   none          orange       black    
## 15 Jango Fett           183  79   black         tan          brown    
##    birth_year sex   gender    homeworld    species      films     vehicles 
##         <dbl> <chr> <chr>     <chr>        <chr>        <list>    <list>   
##  1       24   male  masculine Tatooine     Human        <chr [1]> <chr [0]>
##  2       57   male  masculine Stewjon      Human        <chr [6]> <chr [1]>
##  3       29   male  masculine Corellia     Human        <chr [4]> <chr [0]>
##  4       44   male  masculine Rodia        Rodian       <chr [1]> <chr [0]>
##  5       21   male  masculine Corellia     Human        <chr [3]> <chr [1]>
##  6       82   male  masculine Naboo        Human        <chr [5]> <chr [0]>
##  7       31.5 male  masculine Kamino       Human        <chr [3]> <chr [0]>
##  8       31   male  masculine Socorro      Human        <chr [2]> <chr [0]>
##  9       41   male  masculine Mon Cala     Mon Calamari <chr [2]> <chr [0]>
## 10       52   male  masculine Naboo        Gungan       <chr [2]> <chr [0]>
## 11       54   male  masculine Dathomir     Zabrak       <chr [1]> <chr [1]>
## 12       72   male  masculine Haruun Kal   Human        <chr [3]> <chr [0]>
## 13       92   male  masculine Cerea        Cerean       <chr [3]> <chr [0]>
## 14       22   male  masculine Dorin        Kel Dor      <chr [3]> <chr [0]>
## 15       66   male  masculine Concord Dawn Human        <chr [1]> <chr [0]>
##    starships
##    <list>   
##  1 <chr [1]>
##  2 <chr [5]>
##  3 <chr [2]>
##  4 <chr [0]>
##  5 <chr [1]>
##  6 <chr [0]>
##  7 <chr [1]>
##  8 <chr [1]>
##  9 <chr [0]>
## 10 <chr [0]>
## 11 <chr [1]>
## 12 <chr [0]>
## 13 <chr [0]>
## 14 <chr [1]>
## 15 <chr [0]>

 

📝Ejercicio 5: añadido al filtro anterior, selecciona solo las columnas name, mass, eye_color, birth_year

  • Solución:
# Solo name, mass, eye_color, birth_year
filtro %>% select(c(name, mass, eye_color, birth_year))
## # A tibble: 15 × 4
##    name               mass eye_color birth_year
##    <chr>             <dbl> <chr>          <dbl>
##  1 Biggs Darklighter  84   brown           24  
##  2 Obi-Wan Kenobi     77   blue-gray       57  
##  3 Han Solo           80   brown           29  
##  4 Greedo             74   black           44  
##  5 Wedge Antilles     77   hazel           21  
##  6 Palpatine          75   yellow          82  
##  7 Boba Fett          78.2 brown           31.5
##  8 Lando Calrissian   79   brown           31  
##  9 Ackbar             83   orange          41  
## 10 Jar Jar Binks      66   orange          52  
## 11 Darth Maul         80   yellow          54  
## 12 Mace Windu         84   brown           72  
## 13 Ki-Adi-Mundi       82   yellow          92  
## 14 Plo Koon           80   black           22  
## 15 Jango Fett         79   brown           66

 

📝Ejercicio 5: selecciona solo las columnas que contengan variables numéricas.

  • Solución:
starwars %>% select(where(is.numeric))
## # A tibble: 87 × 3
##    height  mass birth_year
##     <int> <dbl>      <dbl>
##  1    172    77       19  
##  2    167    75      112  
##  3     96    32       33  
##  4    202   136       41.9
##  5    150    49       19  
##  6    178   120       52  
##  7    165    75       47  
##  8     97    32       NA  
##  9    183    84       24  
## 10    182    77       57  
## # … with 77 more rows

 

📝Ejercicio 6: añadido a la selección anterior, coloca los años de nacimiento como primera columna y cambia los nombres a castellano.

  • Solución:
starwars %>%
  select(where(is.numeric)) %>%
  relocate(height, mass, .after = birth_year) %>%
  rename(edad = birth_year, altura = height, peso = mass)
## # A tibble: 87 × 3
##     edad altura  peso
##    <dbl>  <int> <dbl>
##  1  19      172    77
##  2 112      167    75
##  3  33       96    32
##  4  41.9    202   136
##  5  19      150    49
##  6  52      178   120
##  7  47      165    75
##  8  NA       97    32
##  9  24      183    84
## 10  57      182    77
## # … with 77 more rows

 

📝Ejercicio 7: calcula una nueva columna que indique el número de naves que ha pilotado cada persona (escribe ? starwars en consola para ver documentación del fichero).

  • Solución:
starwars_numero_naves <- 
  starwars %>%
  mutate(n_naves = map_chr(starships, length))

# Imprimimos todas las columnas
print(starwars_numero_naves, width = Inf)
## # A tibble: 87 × 15
##    name               height  mass hair_color    skin_color  eye_color
##    <chr>               <int> <dbl> <chr>         <chr>       <chr>    
##  1 Luke Skywalker        172    77 blond         fair        blue     
##  2 C-3PO                 167    75 <NA>          gold        yellow   
##  3 R2-D2                  96    32 <NA>          white, blue red      
##  4 Darth Vader           202   136 none          white       yellow   
##  5 Leia Organa           150    49 brown         light       brown    
##  6 Owen Lars             178   120 brown, grey   light       blue     
##  7 Beru Whitesun lars    165    75 brown         light       blue     
##  8 R5-D4                  97    32 <NA>          white, red  red      
##  9 Biggs Darklighter     183    84 black         light       brown    
## 10 Obi-Wan Kenobi        182    77 auburn, white fair        blue-gray
##    birth_year sex    gender    homeworld species films     vehicles  starships
##         <dbl> <chr>  <chr>     <chr>     <chr>   <list>    <list>    <list>   
##  1       19   male   masculine Tatooine  Human   <chr [5]> <chr [2]> <chr [2]>
##  2      112   none   masculine Tatooine  Droid   <chr [6]> <chr [0]> <chr [0]>
##  3       33   none   masculine Naboo     Droid   <chr [7]> <chr [0]> <chr [0]>
##  4       41.9 male   masculine Tatooine  Human   <chr [4]> <chr [0]> <chr [1]>
##  5       19   female feminine  Alderaan  Human   <chr [5]> <chr [1]> <chr [0]>
##  6       52   male   masculine Tatooine  Human   <chr [3]> <chr [0]> <chr [0]>
##  7       47   female feminine  Tatooine  Human   <chr [3]> <chr [0]> <chr [0]>
##  8       NA   none   masculine Tatooine  Droid   <chr [1]> <chr [0]> <chr [0]>
##  9       24   male   masculine Tatooine  Human   <chr [1]> <chr [0]> <chr [1]>
## 10       57   male   masculine Stewjon   Human   <chr [6]> <chr [1]> <chr [5]>
##    n_naves
##    <chr>  
##  1 2      
##  2 0      
##  3 0      
##  4 1      
##  5 0      
##  6 0      
##  7 0      
##  8 0      
##  9 1      
## 10 5      
## # … with 77 more rows
# Solo la columna añadida
starwars %>%
  transmute(n_naves = map_chr(starships, length))
## # A tibble: 87 × 1
##    n_naves
##    <chr>  
##  1 2      
##  2 0      
##  3 0      
##  4 1      
##  5 0      
##  6 0      
##  7 0      
##  8 0      
##  9 1      
## 10 5      
## # … with 77 more rows

 

📝Ejercicio 8: con la columna anterior añadido, crea una nueva variable TRUE/FALSE que nos diga si ha conducido o no alguna nave, y filtra después solo aquellos personajes que han conducido alguna nave.

  • Solución:
# Nueva columna lógica
starwars_numero_naves %>%
  mutate(conducir_nave = n_naves > 0) %>%
  filter(conducir_nave)
## # A tibble: 20 × 16
##    name    height  mass hair_color  skin_color eye_color birth_year sex   gender
##    <chr>    <int> <dbl> <chr>       <chr>      <chr>          <dbl> <chr> <chr> 
##  1 Luke S…    172  77   blond       fair       blue            19   male  mascu…
##  2 Darth …    202 136   none        white      yellow          41.9 male  mascu…
##  3 Biggs …    183  84   black       light      brown           24   male  mascu…
##  4 Obi-Wa…    182  77   auburn, wh… fair       blue-gray       57   male  mascu…
##  5 Anakin…    188  84   blond       fair       blue            41.9 male  mascu…
##  6 Chewba…    228 112   brown       unknown    blue           200   male  mascu…
##  7 Han So…    180  80   brown       fair       brown           29   male  mascu…
##  8 Wedge …    170  77   brown       fair       hazel           21   male  mascu…
##  9 Jek To…    180 110   brown       fair       blue            NA   male  mascu…
## 10 Boba F…    183  78.2 black       fair       brown           31.5 male  mascu…
## 11 Lando …    177  79   black       dark       brown           31   male  mascu…
## 12 Arvel …     NA  NA   brown       fair       brown           NA   male  mascu…
## 13 Nien N…    160  68   none        grey       black           NA   male  mascu…
## 14 Ric Ol…    183  NA   brown       fair       blue            NA   <NA>  <NA>  
## 15 Darth …    175  80   none        red        yellow          54   male  mascu…
## 16 Plo Ko…    188  80   none        orange     black           22   male  mascu…
## 17 Gregar…    185  85   black       dark       brown           NA   male  mascu…
## 18 Grievo…    216 159   none        brown, wh… green, y…       NA   male  mascu…
## 19 Poe Da…     NA  NA   brown       light      brown           NA   male  mascu…
## 20 Padmé …    165  45   brown       light      brown           46   fema… femin…
## # … with 7 more variables: homeworld <chr>, species <chr>, films <list>,
## #   vehicles <list>, starships <list>, n_naves <chr>, conducir_nave <lgl>

 

📝Ejercicio 9: calcula el número de películas en las que han salido y ordena a los personajes de mayor a menor número de películas en las que ha aparecido

  • Solución:
starwars %>% # Calculamos primero el número de películas
  mutate(n_films = map_int(films, length)) %>%
  arrange(desc(n_films)) # Ordenamos de mayor a menor
## # A tibble: 87 × 15
##    name    height  mass hair_color  skin_color eye_color birth_year sex   gender
##    <chr>    <int> <dbl> <chr>       <chr>      <chr>          <dbl> <chr> <chr> 
##  1 R2-D2       96    32 <NA>        white, bl… red             33   none  mascu…
##  2 C-3PO      167    75 <NA>        gold       yellow         112   none  mascu…
##  3 Obi-Wa…    182    77 auburn, wh… fair       blue-gray       57   male  mascu…
##  4 Luke S…    172    77 blond       fair       blue            19   male  mascu…
##  5 Leia O…    150    49 brown       light      brown           19   fema… femin…
##  6 Chewba…    228   112 brown       unknown    blue           200   male  mascu…
##  7 Yoda        66    17 white       green      brown          896   male  mascu…
##  8 Palpat…    170    75 grey        pale       yellow          82   male  mascu…
##  9 Darth …    202   136 none        white      yellow          41.9 male  mascu…
## 10 Han So…    180    80 brown       fair       brown           29   male  mascu…
## # … with 77 more rows, and 6 more variables: homeworld <chr>, species <chr>,
## #   films <list>, vehicles <list>, starships <list>, n_films <int>

 

📝Ejercicio 10: selecciona 7 personajes al azar.

  • Solución:
# Una extracción aleatoria
starwars %>% slice_sample(n = 7)
## # A tibble: 7 × 14
##   name     height  mass hair_color skin_color eye_color birth_year sex   gender 
##   <chr>     <int> <dbl> <chr>      <chr>      <chr>          <dbl> <chr> <chr>  
## 1 Cliegg …    183    NA brown      fair       blue              82 male  mascul…
## 2 Sebulba     112    40 none       grey, red  orange            NA male  mascul…
## 3 C-3PO       167    75 <NA>       gold       yellow           112 none  mascul…
## 4 Cordé       157    NA brown      light      brown             NA fema… femini…
## 5 Jango F…    183    79 black      tan        brown             66 male  mascul…
## 6 Lama Su     229    88 none       grey       black             NA male  mascul…
## 7 San Hill    191    NA none       grey       gold              NA male  mascul…
## # … with 5 more variables: homeworld <chr>, species <chr>, films <list>,
## #   vehicles <list>, starships <list>
# otra (que sale distinta, claro)
starwars %>% slice_sample(n = 7)
## # A tibble: 7 × 14
##   name      height  mass hair_color skin_color eye_color birth_year sex   gender
##   <chr>      <int> <dbl> <chr>      <chr>      <chr>          <dbl> <chr> <chr> 
## 1 Captain …     NA  NA   unknown    unknown    unknown         NA   <NA>  <NA>  
## 2 Ki-Adi-M…    198  82   white      pale       yellow          92   male  mascu…
## 3 Boba Fett    183  78.2 black      fair       brown           31.5 male  mascu…
## 4 Darth Ma…    175  80   none       red        yellow          54   male  mascu…
## 5 Bail Pre…    191  NA   black      tan        brown           67   male  mascu…
## 6 Chewbacca    228 112   brown      unknown    blue           200   male  mascu…
## 7 Palpatine    170  75   grey       pale       yellow          82   male  mascu…
## # … with 5 more variables: homeworld <chr>, species <chr>, films <list>,
## #   vehicles <list>, starships <list>

 

📝Ejercicio 11: selecciona los 5 personajes que en más películas han salido y los 5 que menos.

  • Solución:
# personajes que en más películas han salido (metiendo empates)
starwars  %>%
  mutate(n_films = map_int(films, length)) %>%
  slice_max(n_films, n = 5)
## # A tibble: 8 × 15
##   name     height  mass hair_color  skin_color eye_color birth_year sex   gender
##   <chr>     <int> <dbl> <chr>       <chr>      <chr>          <dbl> <chr> <chr> 
## 1 R2-D2        96    32 <NA>        white, bl… red               33 none  mascu…
## 2 C-3PO       167    75 <NA>        gold       yellow           112 none  mascu…
## 3 Obi-Wan…    182    77 auburn, wh… fair       blue-gray         57 male  mascu…
## 4 Luke Sk…    172    77 blond       fair       blue              19 male  mascu…
## 5 Leia Or…    150    49 brown       light      brown             19 fema… femin…
## 6 Chewbac…    228   112 brown       unknown    blue             200 male  mascu…
## 7 Yoda         66    17 white       green      brown            896 male  mascu…
## 8 Palpati…    170    75 grey        pale       yellow            82 male  mascu…
## # … with 6 more variables: homeworld <chr>, species <chr>, films <list>,
## #   vehicles <list>, starships <list>, n_films <int>
# personajes que en más películas han salido (sin empates)
starwars %>%
  mutate(n_films = map_int(films, length)) %>%
  slice_max(n_films, n = 5, with_ties = FALSE)
## # A tibble: 5 × 15
##   name     height  mass hair_color  skin_color eye_color birth_year sex   gender
##   <chr>     <int> <dbl> <chr>       <chr>      <chr>          <dbl> <chr> <chr> 
## 1 R2-D2        96    32 <NA>        white, bl… red               33 none  mascu…
## 2 C-3PO       167    75 <NA>        gold       yellow           112 none  mascu…
## 3 Obi-Wan…    182    77 auburn, wh… fair       blue-gray         57 male  mascu…
## 4 Luke Sk…    172    77 blond       fair       blue              19 male  mascu…
## 5 Leia Or…    150    49 brown       light      brown             19 fema… femin…
## # … with 6 more variables: homeworld <chr>, species <chr>, films <list>,
## #   vehicles <list>, starships <list>, n_films <int>
# personajes que en menos películas han salido (metiendo empates)
starwars %>%
  mutate(n_films = map_int(films, length)) %>%
  slice_min(n_films, n = 5)
## # A tibble: 46 × 15
##    name     height  mass hair_color skin_color eye_color birth_year sex   gender
##    <chr>     <int> <dbl> <chr>      <chr>      <chr>          <dbl> <chr> <chr> 
##  1 R5-D4        97    32 <NA>       white, red red               NA none  mascu…
##  2 Biggs D…    183    84 black      light      brown             24 male  mascu…
##  3 Greedo      173    74 <NA>       green      black             44 male  mascu…
##  4 Jek Ton…    180   110 brown      fair       blue              NA male  mascu…
##  5 IG-88       200   140 none       metal      red               15 none  mascu…
##  6 Bossk       190   113 none       green      red               53 male  mascu…
##  7 Lobot       175    79 none       light      blue              37 male  mascu…
##  8 Mon Mot…    150    NA auburn     fair       blue              48 fema… femin…
##  9 Arvel C…     NA    NA brown      fair       brown             NA male  mascu…
## 10 Wicket …     88    20 brown      brown      brown              8 male  mascu…
## # … with 36 more rows, and 6 more variables: homeworld <chr>, species <chr>,
## #   films <list>, vehicles <list>, starships <list>, n_films <int>
# personajes que en menos películas han salido (sin empates)
starwars %>%
  mutate(n_films = map_int(films, length)) %>%
  slice_min(n_films, n = 5, with_ties = FALSE)
## # A tibble: 5 × 15
##   name      height  mass hair_color skin_color eye_color birth_year sex   gender
##   <chr>      <int> <dbl> <chr>      <chr>      <chr>          <dbl> <chr> <chr> 
## 1 R5-D4         97    32 <NA>       white, red red               NA none  mascu…
## 2 Biggs Da…    183    84 black      light      brown             24 male  mascu…
## 3 Greedo       173    74 <NA>       green      black             44 male  mascu…
## 4 Jek Tono…    180   110 brown      fair       blue              NA male  mascu…
## 5 IG-88        200   140 none       metal      red               15 none  mascu…
## # … with 6 more variables: homeworld <chr>, species <chr>, films <list>,
## #   vehicles <list>, starships <list>, n_films <int>

 

📝Ejercicio 12: selecciona solo las columnas que se refieren a variables de color (ojos, piel, pelo) (con sufijo "color")

  • Solución:
# Contiene "color" independientemente de que sea sufijo o prefijo
starwars %>% select(contains("color"))
## # A tibble: 87 × 3
##    hair_color    skin_color  eye_color
##    <chr>         <chr>       <chr>    
##  1 blond         fair        blue     
##  2 <NA>          gold        yellow   
##  3 <NA>          white, blue red      
##  4 none          white       yellow   
##  5 brown         light       brown    
##  6 brown, grey   light       blue     
##  7 brown         light       blue     
##  8 <NA>          white, red  red      
##  9 black         light       brown    
## 10 auburn, white fair        blue-gray
## # … with 77 more rows
# Contiene "color" como sufijo
starwars %>% select(ends_with("color"))
## # A tibble: 87 × 3
##    hair_color    skin_color  eye_color
##    <chr>         <chr>       <chr>    
##  1 blond         fair        blue     
##  2 <NA>          gold        yellow   
##  3 <NA>          white, blue red      
##  4 none          white       yellow   
##  5 brown         light       brown    
##  6 brown, grey   light       blue     
##  7 brown         light       blue     
##  8 <NA>          white, red  red      
##  9 black         light       brown    
## 10 auburn, white fair        blue-gray
## # … with 77 more rows

Profundizando tidyverse: encuestas electorales

Vamos a profundizar un poco en el uso de funciones tidyverse para el análisis de datos de encuestas, datos de Our World in Data y datos de Spotify

En la denostada wikipedia se publican de forma bastante completa las encuestas electorales previas a las elecciones de un país, en este caso de España. El enlace donde están los datos es https://en.wikipedia.org/wiki/Opinion_polling_for_the_next_Spanish_general_election

Lo que vamos a hacer primero extraer la información de la web, analizando desde R su código HTML y quedándonos con las encuestas de 2021 y 2022. Para ello haremos uso del paquete rvest (cargaremos también tidyverse):

De esta manera leeremos el HTML, localizaremos las tablas de datos y seleccionaremos solo las dos primeras (encuestas de 2022 y 2021).

library(rvest)
library(tidyverse)
wiki <-
  paste0("https://en.wikipedia.org/wiki/Opinion_polling_for_the_next_Spanish_general_election")

# Leemos html
html <- read_html(wiki)

# Seleccionamos las tablas del HTML
tablas <- html_elements(html, ".wikitable")

# Obtenemos las dos primeras tablas: encuestas de 2022 y 2021
encuestas_2022 <- html_table(tablas[[1]])
encuestas_2022
## # A tibble: 14 × 21
##    `Polling firm/Com… `Fieldwork date` `Sample size` Turnout ``     ``     ``   
##    <chr>              <chr>            <chr>         <chr>   <chr>  <chr>  <chr>
##  1 Polling firm/Comm… Fieldwork date   Sample size   Turnout ""     ""     ""   
##  2 ElectoPanel/Elect… 21–28 Jan        1,161         ?       "24.2… "22.5… "20.…
##  3 DYM/Henneo[2]      19–23 Jan        1,008         ?       "25.7… "26.9… "17.…
##  4 KeyData/Público[3] 21 Jan           ?             68.1    "26.0… "25.6… "17.…
##  5 ElectoPanel/Elect… 14–20 Jan        1,190         ?       "24.4… "22.9… "20.…
##  6 Celeste-Tel/Onda … 10–14 Jan        1,100         ?       "26.2… "27.2… "16.…
##  7 InvyMark/laSexta[… 10–14 Jan        ?             ?       "27.3" "27.9" "16.…
##  8 CIS (SocioMétrica… 3–14 Jan         3,777         59.3    "26.9" "22.4" "19.…
##  9 CIS[9][10][11]     3–14 Jan         3,777         ?       "28.5… "21.5… "14.…
## 10 IMOP/El Confidenc… 3–14 Jan         1,312         ?       "26.4… "24.9… "17.…
## 11 ElectoPanel/Elect… 7–13 Jan         1,317         ?       "24.5… "23.3… "20.…
## 12 Simple Lógica/elD… 3–13 Jan         1,039         63.0    "24.6" "24.3" "18.…
## 13 ElectoPanel/Elect… 31 Dec–6 Jan     1,823         ?       "24.9… "23.5… "20.…
## 14 Data10/OKDiario[1… 3–5 Jan          1,000         ?       "25.4… "27.8… "17.…
## # … with 14 more variables:  <chr>,  <chr>,  <chr>,  <chr>,  <chr>, PNV <chr>,
## #    <chr>,  <chr>,  <chr>,  <chr>,  <chr>, PRC <chr>,  <chr>, Lead <chr>
encuestas_2021 <- html_table(tablas[[2]])
encuestas_2021
## # A tibble: 209 × 21
##    `Polling firm/Com… `Fieldwork date` `Sample size` Turnout ``     ``     ``   
##    <chr>              <chr>            <chr>         <chr>   <chr>  <chr>  <chr>
##  1 Polling firm/Comm… Fieldwork date   Sample size   Turnout ""     ""     ""   
##  2 ElectoPanel/Elect… 24–30 Dec        1,189         ?       "24.9… "23.9… "19.…
##  3 40dB/Prisa[18][19] 23–30 Dec        2,000         ?       "26.1… "23.5… "18.…
##  4 IMOP/El Confidenc… 20–30 Dec        1,315         ?       "25.2… "25.0… "18.…
##  5 SocioMétrica/El E… 20–30 Dec        3,000         ?       "25.5… "24.2… "17.…
##  6 PSOE[22]           27 Dec           ?             ?       "29.0" "22.0" "17.…
##  7 Sigma Dos/Antena … 26 Dec           ?             ?       "25.7… "28.8… "15.…
##  8 Sigma Dos/El Mund… 20–24 Dec        2,619         ?       "26.0… "27.4… "16.…
##  9 ElectoPanel/Elect… 17–23 Dec        1,299         ?       "25.3… "24.6… "19.…
## 10 KeyData/Público[2… 22 Dec           ?             67.1    "25.7… "26.4… "17.…
## # … with 199 more rows, and 14 more variables:  <chr>,  <chr>,  <chr>,  <chr>,
## #    <chr>, PNV <chr>,  <chr>,  <chr>,  <chr>,  <chr>,  <chr>, PRC <chr>,
## #   TE <chr>, Lead <chr>

Nombrar columnas

Dado que la mayoría de las columnas tienen como nombre de partido el logo del mismo, vamos a renombrar las variables.

nombre_cols <-
  c("casa", "fechas", "muestra", "participacion", "PSOE", "PP", "Vox",
    "UP", "Cs", "ERC", "MP", "JxCat",   "PNV",  "EHBildu", "CUP",
    "CC", "BNG", "NA+", "PRC", "EV", "ventaja")
names(encuestas_2022) <- names(encuestas_2021) <- nombre_cols
encuestas_2022
## # A tibble: 14 × 21
##    casa   fechas muestra participacion PSOE  PP    Vox   UP    Cs    ERC   MP   
##    <chr>  <chr>  <chr>   <chr>         <chr> <chr> <chr> <chr> <chr> <chr> <chr>
##  1 Polli… Field… Sample… Turnout       ""    ""    ""    ""    ""    ""    ""   
##  2 Elect… 21–28… 1,161   ?             "24.… "22.… "20.… "13.… "3.3… "3.5… "2.5…
##  3 DYM/H… 19–23… 1,008   ?             "25.… "26.… "17.… "11.… "3.4… "–"   "2.8…
##  4 KeyDa… 21 Jan ?       68.1          "26.… "25.… "17.… "11.… "2.9… "3.5… "3.0…
##  5 Elect… 14–20… 1,190   ?             "24.… "22.… "20.… "12.… "3.2… "3.5… "2.5…
##  6 Celes… 10–14… 1,100   ?             "26.… "27.… "16.… "11.… "3.4… "3.0… "3.6…
##  7 InvyM… 10–14… ?       ?             "27.… "27.… "16.… "10.… "1.3" "–"   "3.0"
##  8 CIS (… 3–14 … 3,777   59.3          "26.… "22.… "19.… "11.… "3.0" "3.1" "2.6"
##  9 CIS[9… 3–14 … 3,777   ?             "28.… "21.… "14.… "13.… "4.0… "3.0… "2.8…
## 10 IMOP/… 3–14 … 1,312   ?             "26.… "24.… "17.… "11.… "2.6… "3.4… "2.5…
## 11 Elect… 7–13 … 1,317   ?             "24.… "23.… "20.… "12.… "3.3… "3.5… "2.6…
## 12 Simpl… 3–13 … 1,039   63.0          "24.… "24.… "18.… "11.… "2.5" "–"   "2.3"
## 13 Elect… 31 De… 1,823   ?             "24.… "23.… "20.… "12.… "3.2… "3.5… "2.6…
## 14 Data1… 3–5 J… 1,000   ?             "25.… "27.… "17.… "10.… "2.7… "3.2… "3.2…
## # … with 10 more variables: JxCat <chr>, PNV <chr>, EHBildu <chr>, CUP <chr>,
## #   CC <chr>, BNG <chr>, NA+ <chr>, PRC <chr>, EV <chr>, ventaja <chr>
encuestas_2021
## # A tibble: 209 × 21
##    casa   fechas muestra participacion PSOE  PP    Vox   UP    Cs    ERC   MP   
##    <chr>  <chr>  <chr>   <chr>         <chr> <chr> <chr> <chr> <chr> <chr> <chr>
##  1 Polli… Field… Sample… Turnout       ""    ""    ""    ""    ""    ""    ""   
##  2 Elect… 24–30… 1,189   ?             "24.… "23.… "19.… "11.… "3.2… "3.5… "2.7…
##  3 40dB/… 23–30… 2,000   ?             "26.… "23.… "18.… "11.… "3.6… "?13" "3.6…
##  4 IMOP/… 20–30… 1,315   ?             "25.… "25.… "18.… "12.… "2.8… "3.2… "2.7…
##  5 Socio… 20–30… 3,000   ?             "25.… "24.… "17.… "12.… "4.3… "2.8… "3.2…
##  6 PSOE[… 27 Dec ?       ?             "29.… "22.… "17.… "11.… "–"   "–"   "–"  
##  7 Sigma… 26 Dec ?       ?             "25.… "28.… "15.… "10.… "3.2… "3.0… "3.0…
##  8 Sigma… 20–24… 2,619   ?             "26.… "27.… "16.… "10.… "3.1… "3.0… "3.1…
##  9 Elect… 17–23… 1,299   ?             "25.… "24.… "19.… "11.… "3.2… "3.5… "2.7…
## 10 KeyDa… 22 Dec ?       67.1          "25.… "26.… "17.… "11.… "3.1… "3.4… "3.1…
## # … with 199 more rows, and 10 more variables: JxCat <chr>, PNV <chr>,
## #   EHBildu <chr>, CUP <chr>, CC <chr>, BNG <chr>, NA+ <chr>, PRC <chr>,
## #   EV <chr>, ventaja <chr>

Eliminar filas

Tras la lectura sin salirnos de R, tenemos dos tablas de encuestas electorales, a las que les vamos a quitar la primera fila (vacía) con slice(-1).

encuestas_2022 <- encuestas_2022 %>% slice(-1)
encuestas_2022
## # A tibble: 13 × 21
##    casa   fechas muestra participacion PSOE  PP    Vox   UP    Cs    ERC   MP   
##    <chr>  <chr>  <chr>   <chr>         <chr> <chr> <chr> <chr> <chr> <chr> <chr>
##  1 Elect… 21–28… 1,161   ?             24.2… 22.5… 20.9… 13.1… 3.31  3.513 2.55 
##  2 DYM/H… 19–23… 1,008   ?             25.7… 26.9… 17.1… 11.6… 3.42… –     2.82…
##  3 KeyDa… 21 Jan ?       68.1          26.0… 25.6… 17.4… 11.5… 2.91  3.513 3.04 
##  4 Elect… 14–20… 1,190   ?             24.4… 22.9… 20.7… 12.7… 3.21  3.514 2.55 
##  5 Celes… 10–14… 1,100   ?             26.2… 27.2… 16.5… 11.0… 3.42  3.012 3.65 
##  6 InvyM… 10–14… ?       ?             27.3  27.9  16.5  10.9  1.3   –     3.0  
##  7 CIS (… 3–14 … 3,777   59.3          26.9  22.4  19.0  11.7  3.0   3.1   2.6  
##  8 CIS[9… 3–14 … 3,777   ?             28.5… 21.5… 14.7… 13.1… 4.03  3.013 2.83 
##  9 IMOP/… 3–14 … 1,312   ?             26.4… 24.9… 17.9… 11.8… 2.61  3.414 2.53 
## 10 Elect… 7–13 … 1,317   ?             24.5… 23.3… 20.5… 12.4… 3.31  3.514 2.66 
## 11 Simpl… 3–13 … 1,039   63.0          24.6  24.3  18.7  11.1  2.5   –     2.3  
## 12 Elect… 31 De… 1,823   ?             24.9… 23.5… 20.2… 12.0… 3.21  3.514 2.65 
## 13 Data1… 3–5 J… 1,000   ?             25.4… 27.8… 17.0… 10.9… 2.71  3.213 3.23 
## # … with 10 more variables: JxCat <chr>, PNV <chr>, EHBildu <chr>, CUP <chr>,
## #   CC <chr>, BNG <chr>, NA+ <chr>, PRC <chr>, EV <chr>, ventaja <chr>
encuestas_2021 <- encuestas_2021 %>% slice(-1)
encuestas_2021
## # A tibble: 208 × 21
##    casa   fechas muestra participacion PSOE  PP    Vox   UP    Cs    ERC   MP   
##    <chr>  <chr>  <chr>   <chr>         <chr> <chr> <chr> <chr> <chr> <chr> <chr>
##  1 Elect… 24–30… 1,189   ?             24.9… 23.9… 19.9… 11.8… 3.21  3.514 2.76 
##  2 40dB/… 23–30… 2,000   ?             26.1… 23.5… 18.3… 11.8… 3.62… ?13   3.63…
##  3 IMOP/… 20–30… 1,315   ?             25.2… 25.0… 18.6… 12.1… 2.81  3.213 2.73 
##  4 Socio… 20–30… 3,000   ?             25.5… 24.2… 17.7… 12.3… 4.33  2.812 3.25 
##  5 PSOE[… 27 Dec ?       ?             29.0  22.0  17.0  11.0  –     –     –    
##  6 Sigma… 26 Dec ?       ?             25.7… 28.8… 15.7… 10.6… 3.21  3.0?  3.06 
##  7 Sigma… 20–24… 2,619   ?             26.0… 27.4… 16.6… 10.9… 3.11  3.012 3.16 
##  8 Elect… 17–23… 1,299   ?             25.3… 24.6… 19.5… 11.4… 3.21  3.514 2.76 
##  9 KeyDa… 22 Dec ?       67.1          25.7… 26.4… 17.1… 11.1… 3.11  3.413 3.14 
## 10 DYM/H… 15–19… 1,012   ?             25.6… 27.6… 16.9… 10.6… 4.72… –     3.22…
## # … with 198 more rows, and 10 more variables: JxCat <chr>, PNV <chr>,
## #   EHBildu <chr>, CUP <chr>, CC <chr>, BNG <chr>, NA+ <chr>, PRC <chr>,
## #   EV <chr>, ventaja <chr>

Añadir columna de año

En cada tabla vamos a añadir una nueva columna que indique el año.

encuestas_2022 <- encuestas_2022 %>% mutate(anno = 2022)
encuestas_2021 <- encuestas_2021 %>% mutate(anno = 2021)

Juntar tablas

Dado que queremos un solo dataset con las encuestas de ambos años, vamos a juntar ambas tablas con rbind() para tener una sola tabla encuestas.

encuestas <- rbind(encuestas_2022, encuestas_2021)
DT::datatable(encuestas, options = list(pageLength = 10),
              caption = "Encuestas de 2021 y 2022")

Convertir a numéricas

Si te fijas los valores de muchas variables son erróneos, como tamaño de la muestra o participación: son de tipo texto cuando deberían ser numéricas.

encuestas
## # A tibble: 221 × 22
##    casa   fechas muestra participacion PSOE  PP    Vox   UP    Cs    ERC   MP   
##    <chr>  <chr>  <chr>   <chr>         <chr> <chr> <chr> <chr> <chr> <chr> <chr>
##  1 Elect… 21–28… 1,161   ?             24.2… 22.5… 20.9… 13.1… 3.31  3.513 2.55 
##  2 DYM/H… 19–23… 1,008   ?             25.7… 26.9… 17.1… 11.6… 3.42… –     2.82…
##  3 KeyDa… 21 Jan ?       68.1          26.0… 25.6… 17.4… 11.5… 2.91  3.513 3.04 
##  4 Elect… 14–20… 1,190   ?             24.4… 22.9… 20.7… 12.7… 3.21  3.514 2.55 
##  5 Celes… 10–14… 1,100   ?             26.2… 27.2… 16.5… 11.0… 3.42  3.012 3.65 
##  6 InvyM… 10–14… ?       ?             27.3  27.9  16.5  10.9  1.3   –     3.0  
##  7 CIS (… 3–14 … 3,777   59.3          26.9  22.4  19.0  11.7  3.0   3.1   2.6  
##  8 CIS[9… 3–14 … 3,777   ?             28.5… 21.5… 14.7… 13.1… 4.03  3.013 2.83 
##  9 IMOP/… 3–14 … 1,312   ?             26.4… 24.9… 17.9… 11.8… 2.61  3.414 2.53 
## 10 Elect… 7–13 … 1,317   ?             24.5… 23.3… 20.5… 12.4… 3.31  3.514 2.66 
## # … with 211 more rows, and 11 more variables: JxCat <chr>, PNV <chr>,
## #   EHBildu <chr>, CUP <chr>, CC <chr>, BNG <chr>, NA+ <chr>, PRC <chr>,
## #   EV <chr>, ventaja <chr>, anno <dbl>

Para ello vamos antes a eliminar las comas"," que separan los millares de los números, con gsub(). Dicha orden nos permite sustituir en un vector los caracteres que queramos. Por ejemplo, de un vector de palabras vamos a cambiar la letra a por un punto *: primero le indicamos el patrón a buscar, después el valor nuevo que le daremos, y por último la variable en la que lo vamos a aplicar.

variable <- c("hola", "cama", "elefante", "cerrojo", "león", "gata")
gsub("a", "*", variable)
## [1] "hol*"     "c*m*"     "elef*nte" "cerrojo"  "león"     "g*t*"

Con esta función localizaremos las "," de muestra para sustituirlas por "" (sin nada), y lo mismo haremos con "?" en la variable participacion con los datos ausentes "?".

encuestas_depurado <-
  encuestas %>%
  # Quitamos "," como millares en números
  mutate(muestra = gsub("?", "", gsub(",", "", muestra)),
         participacion = gsub("?", NA, participacion))
encuestas_depurado
## # A tibble: 221 × 22
##    casa   fechas muestra participacion PSOE  PP    Vox   UP    Cs    ERC   MP   
##    <chr>  <chr>  <chr>   <chr>         <chr> <chr> <chr> <chr> <chr> <chr> <chr>
##  1 Elect… 21–28… 1161    <NA>          24.2… 22.5… 20.9… 13.1… 3.31  3.513 2.55 
##  2 DYM/H… 19–23… 1008    <NA>          25.7… 26.9… 17.1… 11.6… 3.42… –     2.82…
##  3 KeyDa… 21 Jan ?       <NA>          26.0… 25.6… 17.4… 11.5… 2.91  3.513 3.04 
##  4 Elect… 14–20… 1190    <NA>          24.4… 22.9… 20.7… 12.7… 3.21  3.514 2.55 
##  5 Celes… 10–14… 1100    <NA>          26.2… 27.2… 16.5… 11.0… 3.42  3.012 3.65 
##  6 InvyM… 10–14… ?       <NA>          27.3  27.9  16.5  10.9  1.3   –     3.0  
##  7 CIS (… 3–14 … 3777    <NA>          26.9  22.4  19.0  11.7  3.0   3.1   2.6  
##  8 CIS[9… 3–14 … 3777    <NA>          28.5… 21.5… 14.7… 13.1… 4.03  3.013 2.83 
##  9 IMOP/… 3–14 … 1312    <NA>          26.4… 24.9… 17.9… 11.8… 2.61  3.414 2.53 
## 10 Elect… 7–13 … 1317    <NA>          24.5… 23.3… 20.5… 12.4… 3.31  3.514 2.66 
## # … with 211 more rows, and 11 more variables: JxCat <chr>, PNV <chr>,
## #   EHBildu <chr>, CUP <chr>, CC <chr>, BNG <chr>, NA+ <chr>, PRC <chr>,
## #   EV <chr>, ventaja <chr>, anno <dbl>

Tras estos cambios, aunque muchas variables numéricas siguen siendo caracter, ya podemos aplicar la función as.numeric(), que aplicaremos a todas las variables menos casa y fechas, con mutate_at, indicándole con vars() primero las columnas a seleccionar (aquellas que no contengan la palabra casa ni fechas), y después la función a aplicar.

encuestas_depurado <-
  encuestas_depurado %>%
  mutate_at(vars(!contains(c("casa", "fechas"))), as.numeric)
encuestas_depurado
## # A tibble: 221 × 22
##    casa   fechas muestra participacion  PSOE    PP   Vox    UP    Cs   ERC    MP
##    <chr>  <chr>    <dbl>         <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
##  1 Elect… 21–28…    1161            NA  24.3  22.6  21.0  13.1  3.31  3.51  2.55
##  2 DYM/H… 19–23…    1008            NA  NA    NA    NA    NA   NA    NA    NA   
##  3 KeyDa… 21 Jan      NA            NA  26.0  25.6  17.5  11.5  2.91  3.51  3.04
##  4 Elect… 14–20…    1190            NA  24.5  23.0  20.8  12.7  3.21  3.51  2.55
##  5 Celes… 10–14…    1100            NA  26.2  27.2  16.6  11.0  3.42  3.01  3.65
##  6 InvyM… 10–14…      NA            NA  27.3  27.9  16.5  10.9  1.3  NA     3   
##  7 CIS (… 3–14 …    3777            NA  26.9  22.4  19    11.7  3     3.1   2.6 
##  8 CIS[9… 3–14 …    3777            NA  28.5  21.6  14.8  13.1  4.03  3.01  2.83
##  9 IMOP/… 3–14 …    1312            NA  26.4  24.9  18.0  11.8  2.61  3.41  2.53
## 10 Elect… 7–13 …    1317            NA  24.6  23.4  20.6  12.4  3.31  3.51  2.66
## # … with 211 more rows, and 11 more variables: JxCat <dbl>, PNV <dbl>,
## #   EHBildu <dbl>, CUP <dbl>, CC <dbl>, BNG <dbl>, NA+ <dbl>, PRC <dbl>,
## #   EV <dbl>, ventaja <dbl>, anno <dbl>

Convertir las fechas de campo

Las fechas del trabajo de campo deben ser tratadas previamente:

  • las fechas de tipo "28 Dec–2 Jan" (por ejemplo, de 2021) deberemos de convertirlas en dos fechas, 2021-12-28 y 2022-01-02.

  • las fechas de tipo "12–14 Jan" (por ejemplo, de 2021) deberemos de convertirlas en dos fechas, 2021-01-12 y 2021-01-14.

  • las fechas de tipo "15 Jan" (por ejemplo, de 2021), las convertiremos a dos fechas, 2021-01-15 y 2021-01-15.

Para ello primero que vamos a hacer va a ser separar las fechas por los guiones - con str_plit() (que nos devolverá una lista).

fechas_intermedias <- str_split(encuestas_depurado$fechas, "–")
fechas_intermedias[1:6]
## [[1]]
## [1] "21"     "28 Jan"
## 
## [[2]]
## [1] "19"     "23 Jan"
## 
## [[3]]
## [1] "21 Jan"
## 
## [[4]]
## [1] "14"     "20 Jan"
## 
## [[5]]
## [1] "10"     "14 Jan"
## 
## [[6]]
## [1] "10"     "14 Jan"

En cada lugar de la lista vemos que tenemos dos fechas en la mayoría de casos: las pondremos en columnas fecha_inicio y fecha_inicial, devolviendo un tibble con map_dfr aplicado a la lista

fechas_intermedias <-
  map_dfr(fechas_intermedias,
          function(x) { tibble("fecha_inicio" = x[1],
                               "fecha_final" = x[2]) })
fechas_intermedias
## # A tibble: 221 × 2
##    fecha_inicio fecha_final
##    <chr>        <chr>      
##  1 21           28 Jan     
##  2 19           23 Jan     
##  3 21 Jan       <NA>       
##  4 14           20 Jan     
##  5 10           14 Jan     
##  6 10           14 Jan     
##  7 3            14 Jan     
##  8 3            14 Jan     
##  9 3            14 Jan     
## 10 7            13 Jan     
## # … with 211 more rows

Los registros donde fecha_final está ausente significa que toma el mismo valor que la fecha de inicio, y así lo modificaremos.

fechas_intermedias <-
  fechas_intermedias %>% 
  mutate(fecha_final = ifelse(is.na(fecha_final),
                              fecha_inicio, fecha_final))
fechas_intermedias
## # A tibble: 221 × 2
##    fecha_inicio fecha_final
##    <chr>        <chr>      
##  1 21           28 Jan     
##  2 19           23 Jan     
##  3 21 Jan       21 Jan     
##  4 14           20 Jan     
##  5 10           14 Jan     
##  6 10           14 Jan     
##  7 3            14 Jan     
##  8 3            14 Jan     
##  9 3            14 Jan     
## 10 7            13 Jan     
## # … with 211 more rows

Las fechas que no tenga mes en fecha_inicio, asumiremos que es el mismo mes que fecha_final: si solo hay números (dos o menos caracteres), obtenemos el mes de la fecha_final (últimos 3 caracteres) y lo pegamos al día.

fechas_intermedias <-
  fechas_intermedias %>% 
  mutate(fecha_inicio =
           ifelse(nchar(fecha_inicio) <= 2,
                  paste(fecha_inicio,
                        paste0(rev(rev(unlist(str_split(fecha_final, "")))[1:3]),
                               collapse = "")), fecha_inicio))
fechas_intermedias
## # A tibble: 221 × 2
##    fecha_inicio fecha_final
##    <chr>        <chr>      
##  1 21 Jan       28 Jan     
##  2 19 Jan       23 Jan     
##  3 21 Jan       21 Jan     
##  4 14 Jan       20 Jan     
##  5 10 Jan       14 Jan     
##  6 10 Jan       14 Jan     
##  7 3 Jan        14 Jan     
##  8 3 Jan        14 Jan     
##  9 3 Jan        14 Jan     
## 10 7 Jan        13 Jan     
## # … with 211 more rows

Esas fechas intermedias las vamos añadir como columnas y, pegándole el año, vamos a convertirlas en datos de tipo fecha. De todas las fechas nos vamos a quedar solo con la fecha_final (recolocando dicha columna tras el nombre de la casa encuestadora).

library(lubridate)
encuestas_depurado <-
  bind_cols(encuestas_depurado,
            fechas_intermedias) %>%
  mutate(fecha_inicio = dmy(paste(fecha_inicio, anno)),
         fecha_final = dmy(paste(fecha_final, anno))) %>%
  select(-c(fechas, anno, fecha_inicio)) %>%
  relocate(fecha_final, .after = casa)
encuestas_depurado
## # A tibble: 221 × 21
##    casa    fecha_final muestra participacion  PSOE    PP   Vox    UP    Cs   ERC
##    <chr>   <date>        <dbl>         <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
##  1 Electo… 2022-01-28     1161            NA  24.3  22.6  21.0  13.1  3.31  3.51
##  2 DYM/He… 2022-01-23     1008            NA  NA    NA    NA    NA   NA    NA   
##  3 KeyDat… 2022-01-21       NA            NA  26.0  25.6  17.5  11.5  2.91  3.51
##  4 Electo… 2022-01-20     1190            NA  24.5  23.0  20.8  12.7  3.21  3.51
##  5 Celest… 2022-01-14     1100            NA  26.2  27.2  16.6  11.0  3.42  3.01
##  6 InvyMa… 2022-01-14       NA            NA  27.3  27.9  16.5  10.9  1.3  NA   
##  7 CIS (S… 2022-01-14     3777            NA  26.9  22.4  19    11.7  3     3.1 
##  8 CIS[9]… 2022-01-14     3777            NA  28.5  21.6  14.8  13.1  4.03  3.01
##  9 IMOP/E… 2022-01-14     1312            NA  26.4  24.9  18.0  11.8  2.61  3.41
## 10 Electo… 2022-01-13     1317            NA  24.6  23.4  20.6  12.4  3.31  3.51
## # … with 211 more rows, and 11 more variables: MP <dbl>, JxCat <dbl>,
## #   PNV <dbl>, EHBildu <dbl>, CUP <dbl>, CC <dbl>, BNG <dbl>, NA+ <dbl>,
## #   PRC <dbl>, EV <dbl>, ventaja <dbl>

Limpiamos nombres de encuestas

Por último, vamos limpiar los nombres de las encuestas eliminando la referencia a los enlaces de la wikipedia

encuestas_depurado <-
  encuestas_depurado %>%
  # Limpiamos nombre encuestas
  mutate(casa = toupper(map_chr(str_split(casa, "\\["),
                                function (y) { y[1] } )))

Consultas

Una vez que tenemos los datos depurados vamos a realizar algunas consultas sencillas usando tidyverse.

¿Cuáles son las 10 encuestas con mayor tamaño muestral?

encuestas_depurado %>% slice_max(muestra, n = 10)
## # A tibble: 10 × 21
##    casa    fecha_final muestra participacion  PSOE    PP   Vox    UP    Cs   ERC
##    <chr>   <date>        <dbl>         <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
##  1 ELECTO… 2021-05-02     4320            NA  27.1  24.0  17.0 12.3   4.03  3.61
##  2 CIS (S… 2021-02-11     3869            NA  28.1  19.7  16.3 11.3   9     3.3 
##  3 CIS     2021-02-11     3869            NA  30.7  18.9  13.6 11.2   9.32  3.52
##  4 CIS (S… 2021-01-25     3862            NA  28.6  22.2  15.9 10     7.4   2.9 
##  5 CIS     2021-01-25     3862            NA  30.7  20.6  13.0 10.7   9.32  2.91
##  6 CIS (S… 2021-04-14     3823            NA  30    20.8  18.8 10.8   4     3.2 
##  7 CIS     2021-04-14     3823            NA  31.5  20.7  15.5 10.7   6.71  2.81
##  8 CIS     2021-03-11     3820            NA  31.3  18.0  15.1  9.62  9.52  3.21
##  9 CIS     2021-06-15     3814            NA  27.4  23.9  13.0 12.0   5.78  3.61
## 10 CIS     2021-05-13     3814            NA  27.9  23.4  13.7 10.4   5.37  3.01
## # … with 11 more variables: MP <dbl>, JxCat <dbl>, PNV <dbl>, EHBildu <dbl>,
## #   CUP <dbl>, CC <dbl>, BNG <dbl>, NA+ <dbl>, PRC <dbl>, EV <dbl>,
## #   ventaja <dbl>

¿Cuáles son las encuestas más recientes?

encuestas_depurado %>% arrange(desc(fecha_final))
## # A tibble: 221 × 21
##    casa    fecha_final muestra participacion  PSOE    PP   Vox    UP    Cs   ERC
##    <chr>   <date>        <dbl>         <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
##  1 ELECTO… 2022-01-28     1161            NA  24.3  22.6  21.0  13.1  3.31  3.51
##  2 DYM/HE… 2022-01-23     1008            NA  NA    NA    NA    NA   NA    NA   
##  3 KEYDAT… 2022-01-21       NA            NA  26.0  25.6  17.5  11.5  2.91  3.51
##  4 ELECTO… 2022-01-20     1190            NA  24.5  23.0  20.8  12.7  3.21  3.51
##  5 CELEST… 2022-01-14     1100            NA  26.2  27.2  16.6  11.0  3.42  3.01
##  6 INVYMA… 2022-01-14       NA            NA  27.3  27.9  16.5  10.9  1.3  NA   
##  7 CIS (S… 2022-01-14     3777            NA  26.9  22.4  19    11.7  3     3.1 
##  8 CIS     2022-01-14     3777            NA  28.5  21.6  14.8  13.1  4.03  3.01
##  9 IMOP/E… 2022-01-14     1312            NA  26.4  24.9  18.0  11.8  2.61  3.41
## 10 ELECTO… 2022-01-13     1317            NA  24.6  23.4  20.6  12.4  3.31  3.51
## # … with 211 more rows, and 11 more variables: MP <dbl>, JxCat <dbl>,
## #   PNV <dbl>, EHBildu <dbl>, CUP <dbl>, CC <dbl>, BNG <dbl>, NA+ <dbl>,
## #   PRC <dbl>, EV <dbl>, ventaja <dbl>

¿Cuáles son las 5 encuestas en las que el PSOE tiene mayor proyección?

encuestas_depurado %>% slice_max(PSOE, n = 5)
## # A tibble: 5 × 21
##   casa     fecha_final muestra participacion  PSOE    PP   Vox    UP    Cs   ERC
##   <chr>    <date>        <dbl>         <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 CIS      2021-04-14     3823            NA  31.5  20.7  15.5 10.7   6.71  2.81
## 2 CIS      2021-03-11     3820            NA  31.3  18.0  15.1  9.62  9.52  3.21
## 3 CIS      2021-02-11     3869            NA  30.7  18.9  13.6 11.2   9.32  3.52
## 4 CIS      2021-01-25     3862            NA  30.7  20.6  13.0 10.7   9.32  2.91
## 5 CIS (SO… 2021-04-14     3823            NA  30    20.8  18.8 10.8   4     3.2 
## # … with 11 more variables: MP <dbl>, JxCat <dbl>, PNV <dbl>, EHBildu <dbl>,
## #   CUP <dbl>, CC <dbl>, BNG <dbl>, NA+ <dbl>, PRC <dbl>, EV <dbl>,
## #   ventaja <dbl>

¿Cuál es la encuesta del CIS en la que el PP tiene mayor proyección?

encuestas_depurado %>%
  filter(casa == "CIS") %>%
  slice_max(PP, n = 1)
## # A tibble: 1 × 21
##   casa  fecha_final muestra participacion  PSOE    PP   Vox    UP    Cs   ERC
##   <chr> <date>        <dbl>         <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 CIS   2021-06-15     3814            NA  27.4  23.9  13.0  12.0  5.78  3.61
## # … with 11 more variables: MP <dbl>, JxCat <dbl>, PNV <dbl>, EHBildu <dbl>,
## #   CUP <dbl>, CC <dbl>, BNG <dbl>, NA+ <dbl>, PRC <dbl>, EV <dbl>,
## #   ventaja <dbl>

¿Cuál es el promedio de las encuestas del PSOE y PP por casa encuestadora?

encuestas_depurado %>%
  select(-fecha_final) %>%
  group_by(casa) %>%
  summarise(media_PSOE = mean(PSOE), media_PP = mean(PP)) %>%
  ungroup()
## # A tibble: 28 × 3
##    casa                            media_PSOE media_PP
##    <chr>                                <dbl>    <dbl>
##  1 40DB/PRISA                            NA       NA  
##  2 ÁGORA INTEGRAL/CANARIAS AHORA         25.8     25.4
##  3 CELESTE-TEL/ONDA CERO                 26.3     27.8
##  4 CIS                                   29.2     21.3
##  5 CIS (SOCIOMÉTRICA)                    27.2     22.1
##  6 DATA10/OKDIARIO                       25.0     29.2
##  7 DEMOSCOPIA Y SERVICIOS/ESDIARIO       25.3     25.9
##  8 DYM/HENNEO                            NA       NA  
##  9 ELECTOPANEL/ELECTOMANÍA               26.2     25.7
## 10 GAD3/ABC                              25.5     29.8
## # … with 18 more rows

¿Cuál es son las 3 casas encuestadoras más sesgada hacia el PSOE (con mayor diferencia de promedio de PSOE vs PP)? ¿Y hacia el PP?

encuestas_depurado %>%
  select(-fecha_final) %>%
  group_by(casa) %>%
  summarise(media_PSOE = mean(PSOE), media_PP = mean(PP)) %>%
  ungroup() %>%
  mutate(diferencia = media_PSOE - media_PP) %>%
  slice_max(diferencia, n = 3)
## # A tibble: 3 × 4
##   casa               media_PSOE media_PP diferencia
##   <chr>                   <dbl>    <dbl>      <dbl>
## 1 CIS                      29.2     21.3       7.94
## 2 PSOE                     29       22         7   
## 3 CIS (SOCIOMÉTRICA)       27.2     22.1       5.13
encuestas_depurado %>%
  select(-fecha_final) %>%
  group_by(casa) %>%
  summarise(media_PSOE = mean(PSOE), media_PP = mean(PP)) %>%
  ungroup() %>%
  mutate(diferencia = media_PP - media_PSOE) %>%
  slice_max(diferencia, n = 3)
## # A tibble: 3 × 4
##   casa               media_PSOE media_PP diferencia
##   <chr>                   <dbl>    <dbl>      <dbl>
## 1 GAD3/ABC                 25.5     29.8       4.36
## 2 DATA10/OKDIARIO          25.0     29.2       4.12
## 3 SIGMA DOS/ANTENA 3       25.3     29.3       3.99

Visualizando datos: incursión a ggplot2

(haz click en las flechas para ver soluciones)

📝Ejercicio 1: del conjunto starwars (del entorno de paquetes tidyverse), filtra solo los registros que no tenga ausente NA en las columnas mass, height, eye_color

  • Solución:
library(tidyverse)
# Eliminamos NA
starwars_filtro <- starwars %>% drop_na(c(mass, height, eye_color))

 

📝Ejercicio 2: con ese conjunto filtrado dibuja un diagrama de puntos enfrentando x = height en el eje X e y = mass en el eje Y.

  • Solución:
ggplot(starwars_filtro, aes(x = height, y = mass)) +
  geom_point()

 

📝Ejercicio 3: modifica el código del gráfico anterior para asignar el tamaño de los puntos en función de la variable mass.

  • Solución:
ggplot(starwars_filtro,
       aes(x = height, y = mass, size = mass)) +
  geom_point()

 

📝Ejercicio 4: modifica el código del gráfico anterior para asignar el color en función de su color de ojos guardado en eye_color. Antes procesa la variable para quedarte con colores reales: si hay dos colores, quédate con el primero; el color "hazel" pásalo a "brown"; los colores "unknown" pásalo a gris.

  • Solución:
# Transformar colores
starwars_filtro <-
   starwars_filtro %>%
    mutate(eye_color =
             case_when(eye_color == "blue-gray" ~ "blue",
                       eye_color == "hazel" ~ "brown",
                       eye_color == "unknown" ~ "gray",
                       eye_color == "green, yellow" ~ "green",
                       TRUE ~ eye_color))

# Visualizamos
ggplot(starwars_filtro,
       aes(x = height, y = mass, size = mass, color = eye_color)) +
  geom_point() +
  scale_color_manual(values =
                       c("black", "blue", "brown", "gray", "green",
                         "orange", "red", "white", "yellow"))

 

📝Ejercicio 5: repite el gráfico anterior localizando ese dato con un peso extremadamente elevado (outlier), elimínalo y vuelve a repetir la visualización.

  • Solución:
# Localizamos el valor
starwars_filtro %>% slice_max(mass, n = 5)
## # A tibble: 5 × 14
##   name    height  mass hair_color skin_color  eye_color birth_year sex    gender
##   <chr>    <int> <dbl> <chr>      <chr>       <chr>          <dbl> <chr>  <chr> 
## 1 Jabba …    175  1358 <NA>       green-tan,… orange         600   herma… mascu…
## 2 Grievo…    216   159 none       brown, whi… green           NA   male   mascu…
## 3 IG-88      200   140 none       metal       red             15   none   mascu…
## 4 Darth …    202   136 none       white       yellow          41.9 male   mascu…
## 5 Tarfful    234   136 brown      brown       blue            NA   male   mascu…
## # … with 5 more variables: homeworld <chr>, species <chr>, films <list>,
## #   vehicles <list>, starships <list>
starwars_filtro %>% slice_max(mass, n = 5) %>% pull(name)
## [1] "Jabba Desilijic Tiure" "Grievous"              "IG-88"                
## [4] "Darth Vader"           "Tarfful"
starwars_filtro <- starwars_filtro %>%
  filter(name != "Jabba Desilijic Tiure")

# Visualizamos
ggplot(starwars_filtro,
       aes(x = height, y = mass,
           size = mass, color = eye_color)) +
  geom_point() +
  scale_color_manual(values =
                       c("black", "blue", "brown", "gray", "green",
                         "orange", "red", "white", "yellow"))

 

📝Ejercicio 6: repite el gráfico anterior eliminando la leyenda del tamaño del punto y cambia el título de la leyenda del color de ojos a castellano. Añade además transparencia alpha = 0.6 a los puntos.

  • Solución:
ggplot(starwars_filtro,
       aes(x = height, y = mass,
           size = mass, color = eye_color)) +
  geom_point(alpha = 0.6) +
  guides(size = "none") +
  scale_color_manual(values =
                       c("black", "blue", "brown", "gray", "green",
                         "orange", "red", "white", "yellow")) +
  labs(color = "color de ojos")

 

📝Ejercicio 7: repite el gráfico modificando los títulos de los ejes (a castellano) y escribiendo título, subtítulo y caption.

  • Solución:
ggplot(starwars_filtro,
       aes(x = height, y = mass,
           size = mass, color = eye_color)) +
  geom_point(alpha = 0.6) +
  guides(size = "none") +
  scale_color_manual(values =
                       c("black", "blue", "brown", "gray", "green",
                         "orange", "red", "white", "yellow")) +
  labs(color = "color de ojos",
       x = "altura (cm)", y = "peso (kg)",
       title = "STARWARS",
       subtitle = "Diagrama de puntos altura vs peso",
       caption = "Autor: Javier Álvarez Liébana | Datos: starwars")

 

📝Ejercicio 8: repite el gráfico anterior explicitando los cortes en los ejes con scale_x_continuous() y scale_y_continuous(): el eje X de 60 a 240 (de 30 en 30 cada marca), el eje Y de 20 a 160 (de 20 en 20 cada marca).

  • Solución:
ggplot(starwars_filtro,
       aes(x = height, y = mass,
           size = mass, color = eye_color)) +
    geom_point(alpha = 0.6) +
    guides(size = "none") +
    scale_color_manual(values =
                           c("black", "blue", "brown", "gray", "green",
                             "orange", "red", "white", "yellow")) +
  scale_y_continuous(breaks = seq(20, 160, by = 20)) +
  scale_x_continuous(breaks = seq(60, 240, by = 30)) +
  labs(color = "color de ojos",
       x = "altura (cm)", y = "peso (kg)",
       title = "STARWARS",
       subtitle = "Diagrama de puntos altura vs peso",
       caption = "Autor: Javier Álvarez Liébana | Datos: starwars")

 

📝Ejercicio 9: del conjunto de datos original, elimina los registros que tengan ausente la variable sex. Agrupa por dicha variable y contabiliza los personajes de cada sexo. Visualízalo en un diagrama de barras vertical, con la escala de colores de scale_fill_tableau(), cambiando el nombre de leyenda y de ejes, y poniéndo títulos y subtítulos.

  • Solución:
library(ggthemes)
starwars_filtro <- starwars %>% drop_na(sex)

# Vertical
ggplot(starwars_filtro %>% group_by(sex) %>% count(),
       aes(x = sex, y = n, fill = sex)) +
  geom_col() +
  scale_fill_tableau() +
  labs(fill = "Sexo",
       x = "Sexo", y = "Número de personajes",
       title = "STARWARS",
       subtitle = "Diagrama de barras verticales",
       caption = "Autor: Javier Álvarez Liébana | Datos: starwars")
# Horizontal
ggplot(starwars_filtro %>% group_by(sex) %>% count(),
       aes(x = sex, y = n, fill = sex)) +
  geom_col() +
  coord_flip() +
  scale_fill_tableau() +
  labs(fill = "Sexo",
       x = "Sexo", y = "Número de personajes",
       title = "STARWARS",
       subtitle = "Diagrama de barras vertical",
       caption = "Autor: Javier Álvarez Liébana | Datos: starwars")

Profundizando en ggplot2

(haz click en las flechas para ver soluciones)

El ejercicio está basado en el gráfico de Tobias Stadler, cuyo código original puedes encontrarlo en Github, al tutorial de Tomás Capretto y al material en R Graph Gallery.

Se ruega citar la autoría del gráfico añadiendo el siguiente caption

caption_chart <- "Dataviz by Tobias Stalder\ntobias-stalder.netlify.app\nSource: TidyX Crew (Ellis Hughes, Patrick Ward)\n Data: github.com/rfordatascience/tidytuesday/blob/master/data/2020/2020-11-24/readme.md"

Los datos provienen originalmente de la «Washington Trails Association», con datos de sendas de senderismo en Washington. Tienes el archivo hiking.csv en la carpeta DATOS. Los datos han sido descargados desde https://github.com/rfordatascience/tidytuesday/blob/master/data/2020/2020-11-24

📝Ejercicio 1: carga los datos hiking.csv y muestra las variables.

  • Solución:
library(tidyverse)
hike_data <- read_csv("./DATOS/hiking.csv")
hike_data 
## # A tibble: 1,958 × 8
##    name    location     length   gain highpoint rating features description     
##    <chr>   <chr>        <chr>   <dbl>     <dbl>  <dbl> <lgl>    <chr>           
##  1 Lake H… Puget Sound… 2.3 mi…    50       330   3.67 NA       "Hike through a…
##  2 Snow L… Snoqualmie … 7.2 mi…  1800      4400   4.16 NA       "A relatively s…
##  3 Skooku… Mount Raini… 7.8 mi…   300      2550   3.68 NA       "Choose between…
##  4 Teneri… Snoqualmie … 5.6 mi…  1585      2370   3.92 NA       "You'll work up…
##  5 Twin F… Snoqualmie … 2.6 mi…   500      1000   4.14 NA       "Visit a trio (…
##  6 Chenui… Mount Raini… 8.0 mi…   500      2200   3.14 NA       "A long walk (o…
##  7 Old Mi… Mount Raini… 3.4 mi…   425      2150   5    NA       "An infrequentl…
##  8 Flamin… Puget Sound… 4.0 mi…   450       425   2.68 NA       "The striking n…
##  9 Salmon… North Casca… 5.4 mi…   300      2400   4    NA       "With gentle te…
## 10 May Va… Issaquah Al… 6.6 mi…  1684      2024   2.96 NA       "This forested …
## # … with 1,948 more rows
glimpse(hike_data)
## Rows: 1,958
## Columns: 8
## $ name        <chr> "Lake Hills Greenbelt", "Snow Lake", "Skookum Flats", "Ten…
## $ location    <chr> "Puget Sound and Islands -- Seattle-Tacoma Area", "Snoqual…
## $ length      <chr> "2.3 miles, roundtrip", "7.2 miles, roundtrip", "7.8 miles…
## $ gain        <dbl> 50, 1800, 300, 1585, 500, 500, 425, 450, 300, 1684, 80, 65…
## $ highpoint   <dbl> 330, 4400, 2550, 2370, 1000, 2200, 2150, 425, 2400, 2024, …
## $ rating      <dbl> 3.67, 4.16, 3.68, 3.92, 4.14, 3.14, 5.00, 2.68, 4.00, 2.96…
## $ features    <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
## $ description <chr> "Hike through a pastoral area first settled and farmed in …

 

📝Ejercicio 2: transforma la variable location para obtener la region (es la primera palabra, antes del " -- ". Para ello puedes usar la función word(), que nos permite seleccionar la palabra enésima de una frase, indicándole en sep = ... el separado entre palabra y palabra. Conviértela a factor la nueva variable region.

  • Solución:
hike_data <-
  hike_data %>%
  mutate(region = as_factor(word(location, 1, sep = " -- ")))

 

📝Ejercicio 3: transforma la variable length para obtener la longitud en millas de la ruta. Está en formato "12.7 miles, roundtrip", así que puedes volver a usar la función word(), y pasar luego la cadena de texto a número.

  • Solución:
hike_data <-
  hike_data %>%
  mutate(miles = as.numeric(word(length, 1)))

 

📝Ejercicio 4: calcula la longitud total (acumulada) y la media de desnivel (gain), con las rutas agrupadas por la variable region, así como el número de rutas por región.

  • Solución:
resumen <-
  hike_data %>%
  group_by(region) %>%
  summarise(sum_miles = sum(miles),
            mean_gain = round(mean(as.numeric(gain))),
            n = n())
resumen
## # A tibble: 11 × 4
##    region                  sum_miles mean_gain     n
##    <fct>                       <dbl>     <dbl> <int>
##  1 Puget Sound and Islands      810.       452   191
##  2 Snoqualmie Region           1915.      2206   219
##  3 Mount Rainier Area          1602.      1874   196
##  4 North Cascades              3347.      2500   301
##  5 Issaquah Alps                383.       973    77
##  6 Central Washington           453.       814    80
##  7 South Cascades              1630.      1649   193
##  8 Central Cascades            2131.      2260   226
##  9 Southwest Washington         825.      1185   123
## 10 Olympic Peninsula           1700.      1572   209
## 11 Eastern Washington          1334.      1591   143

 

📝Ejercicio 5: dibuja un diagrama de barras con la región en el eje X, la suma de millas en el eje Y y el relleno en función del número de rutas.

  • Solución:
ggplot(resumen,
       aes(x = region, y = sum_miles, fill = n)) +
  geom_col() +
  labs(caption = caption_chart)

 

📝Ejercicio 6: repite el ejercicio anterior pero personaliza el tema dando un título a los ejes y una fuente de tamaño adecuada para el eje X. Usa la función str_wrap() para convertir los nombres de regiones en párrafos con salto de línea, indicándole en width la anchura máxima (no romperá palabras a mitad).

  • Solución:
ggplot(resumen,
       aes(x = str_wrap(region, width = 7),
           y = sum_miles, fill = n)) +
  geom_col() +
  labs(caption = caption_chart,
       fill = "Nº de rutas",
       y = "Suma acumulada de millas",
       x = "Región") +
  theme(axis.title.x = element_text(face = "bold", size = 13),
        axis.title.y = element_text(face = "bold", size = 13),
        axis.text.x = element_text(face = "bold", size = 9),
        axis.text.y = element_text(face = "bold", size = 9))

 

📝Ejercicio 7: repite el ejercicio anterior pero usando scale_fill_gradientn() para dar una escala de colores continua (en forma de gradiente) con cuatro colores. Introduce en geom_col() una transparencia de alpha = 0.8

  • Solución:
gg <- 
  ggplot(resumen,
       aes(x = str_wrap(region, width = 7),
           y = sum_miles, fill = n)) +
  geom_col(alpha = 0.8) +
  scale_fill_gradientn("Cantidad de rutas",
                       colours =
                         c("#6C5B7B", "#C06C84", "#F67280", "#F8B195")) +
  labs(caption = caption_chart,
       fill = "Nº de rutas",
       y = "Suma acumulada de millas",
       x = "Región") +
  theme(axis.title.x = element_text(face = "bold", size = 13),
        axis.title.y = element_text(face = "bold", size = 13),
        axis.text.x = element_text(face = "bold", size = 9),
        axis.text.y = element_text(face = "bold", size = 9))
gg

 

📝Ejercicio 8: usa geom_point() para añadir al gráfico anterior la media de desnivel de las rutas. Pon por ejemplo size = 3, alpha = 0.85 y color = "gray20".

  • Solución:
gg <- 
  gg +
  geom_point(aes(x = str_wrap(region, 7), y = mean_gain),
             size = 3, color = "gray20", alpha = 0.85)
gg

 

📝Ejercicio 9: usa coord_polar() para convertir el gráfico anterior a coordenadas polares.

  • Solución:
gg <- gg + coord_polar()
gg

 

📝Ejercicio 10: usa geom_segment() para añadir líneas que vayan del centro hacía fuera, pasando por los puntos de desnivel. Hay que pensar que lo tuviésemos en vertical, indicándole la posición inicial x y final xend del segmento (en este caso, para cada región, así que x = str_wrap(region, 7)), y la posición inicial y = 0 e yend un poco más que el máximo de desnivel.

  • Solución:
gg <- gg +
  geom_segment(aes(x = str_wrap(region, 7), y = 0,
                   xend = str_wrap(region, 7),
                   yend = max(mean_gain) * 1.2),
               linetype = "dashed", color = "gray20") 
gg

 

📝Ejercicio 11: ordena los gajos en orden ascendente con reorder().

  • Solución:
gg <- 
  ggplot(resumen,
       aes(x = reorder(str_wrap(region, width = 7), sum_miles),
           y = sum_miles, fill = n)) +
  geom_col(alpha = 0.8) +
  scale_fill_gradientn("Cantidad de rutas",
                       colours =
                         c("#6C5B7B", "#C06C84", "#F67280", "#F8B195")) +
  labs(caption = caption_chart,
       fill = "Nº de rutas",
       y = "Suma acumulada de millas",
       x = "Región") +
  theme(axis.title.x = element_text(face = "bold", size = 10),
        axis.title.y = element_text(face = "bold", size = 10),
        axis.text.x = element_text(face = "bold", size = 7),
        axis.text.y = element_text(face = "bold", size = 7)) +
  geom_point(aes(x = reorder(str_wrap(region, 7), sum_miles),
                 y = mean_gain),
             size = 3, color = "gray20", alpha = 0.85) +
  coord_polar() +
  geom_segment(aes(x = reorder(str_wrap(region, 7), sum_miles),
                   y = 0,
                   xend = str_wrap(region, 7),
                   yend = max(mean_gain) * 1.2),
               linetype = "dashed", color = "gray20") 
gg

 

📝Ejercicio 12: con annotate() añade en uno de los gajos la indicación de que la altura hasta el punto nos indica el desnivel medio. Usaremos además la fuente "Libre Caslon Text", muy similar a la del gráfico original

  • Solución:
library(sysfonts)
library(showtext)
font_add_google(family = "Libre Caslon Text",
                name = "Libre Caslon Text")
showtext_auto()
gg <- gg +
  annotate(x = 11.2, y = 1500, label = "Desnivel medio",
           geom = "text", angle = -78, color = "gray20",
           size = 2, family = "Libre Caslon Text")
gg

 

📝Ejercicio 13: con annotate() añade en uno de los gajos la indicación de que el radio del gajo nos indica la longitud acumulada de las rutas de esa región. Usaremos además la fuente "Libre Caslon Text", muy similar a la del gráfico original

  • Solución:
library(sysfonts)
library(showtext)
font_add_google(family = "Libre Caslon Text",
                name = "Libre Caslon Text")
showtext_auto()
gg <- gg +
  annotate(x = 11, y = 3200, label = "Longitud acum.",
           geom = "text", angle = 18, color = "gray20",
           size = 2, family = "Libre Caslon Text") 
gg

Por último hacemos que los gajos no empiecen del centro, y añadimos algún ajuste estético más (ver el post original)

gg + 
  scale_y_continuous(limits = c(-1500, 3500),
                     expand = c(0, 0),
                     breaks = c(0, 1000, 2000, 3000)) +
  # Make the guide for the fill discrete
  guides(fill =
           guide_colorsteps(barwidth = 11, barheight = 0.7,
                            title.position = "top",
                            title.hjust = .5)) +
  labs(title = "Senderismo en Washington",
       caption = caption_chart) +
  theme(text = element_text(color = "gray20",
                            family = "Libre Caslon Text"),
        legend.position = "bottom",
        panel.background =
          element_rect(fill = "white", color = "white"),
        panel.grid = element_blank(),
        panel.grid.major.x = element_blank())

Extrayendo información: estadística descriptiva con cualitativas

Scripts usados:

(haz click en las flechas para ver soluciones)

📝Ejercicio 1: usando dplyr de {tidvyerse} calcula la tabla de frecuencias absolutas de la variableskin_color del conjunto de datos de starwars.

  • Solución:
library(tidyverse)
starwars %>% count(skin_color) 
## # A tibble: 31 × 2
##    skin_color              n
##    <chr>               <int>
##  1 blue                    2
##  2 blue, grey              2
##  3 brown                   4
##  4 brown mottle            1
##  5 brown, white            1
##  6 dark                    6
##  7 fair                   17
##  8 fair, green, yellow     1
##  9 gold                    1
## 10 green                   6
## # … with 21 more rows

 

📝Ejercicio 2: repite el ejercicio anterior pero reagrupa los niveles poco frecuentes (poco frecuente definido como que aparezca dos o menos veces) con fct_lump_min().

  • Solución:
starwars %>%
  mutate(fskin_color =
           fct_lump_min(skin_color, min = 3)) %>%
  count(fskin_color) 
## # A tibble: 8 × 2
##   fskin_color     n
##   <fct>       <int>
## 1 brown           4
## 2 dark            6
## 3 fair           17
## 4 green           6
## 5 grey            6
## 6 light          11
## 7 pale            5
## 8 Other          32

 

📝Ejercicio 3: añade a la tabla anterior la tabla de frecuencias relativas de la columna skin_color.

  • Solución:
freq_skin <-
  starwars %>%
  mutate(fskin_color =
           fct_lump_min(skin_color, min = 3)) %>%
  count(fskin_color) %>% 
  rename(ni = n) %>% 
  mutate(fi = ni / sum(ni))
freq_skin
## # A tibble: 8 × 3
##   fskin_color    ni     fi
##   <fct>       <int>  <dbl>
## 1 brown           4 0.0460
## 2 dark            6 0.0690
## 3 fair           17 0.195 
## 4 green           6 0.0690
## 5 grey            6 0.0690
## 6 light          11 0.126 
## 7 pale            5 0.0575
## 8 Other          32 0.368

 

📝Ejercicio 4: recategoriza la variable height usando la función cut con 6 cortes (filtrando antes los valores ausentes). Formatea esa nueva columna como un factor, calculando sus frecuencias y agrupa para no tener clases con menos de 7 valores.

  • Solución:
starwars_fheight <-
  starwars %>%
  filter(!is.na(height)) %>%
  mutate(fheight = factor(cut(height, breaks = 6))) 

# Frecuencias
fct_count(starwars_fheight$fheight)
## # A tibble: 6 × 2
##   f             n
##   <fct>     <int>
## 1 (65.8,99]     7
## 2 (99,132]      2
## 3 (132,165]    10
## 4 (165,198]    51
## 5 (198,231]     9
## 6 (231,264]     2
# Reagrupamos
starwars_fheight <-
  starwars_fheight %>%
  mutate(fheight =
           fct_lump_min(fheight, min = 7,
                        other_level = "otros"))
fct_count(starwars_fheight$fheight)
## # A tibble: 5 × 2
##   f             n
##   <fct>     <int>
## 1 (65.8,99]     7
## 2 (132,165]    10
## 3 (165,198]    51
## 4 (198,231]     9
## 5 otros         4

 

📝Ejercicio 5: genera las frecuencias acumuladas resultantes de la columna recategorizada del ejercicio anterior.

  • Solución:
freq_fheight <-
  starwars_fheight %>% 
  count(fheight) %>%
  rename(ni = n) %>% 
  mutate(fi = ni / sum(ni),
         Ni = cumsum(ni),
         Fi = cumsum(fi))
freq_fheight
## # A tibble: 5 × 5
##   fheight      ni     fi    Ni     Fi
##   <fct>     <int>  <dbl> <int>  <dbl>
## 1 (65.8,99]     7 0.0864     7 0.0864
## 2 (132,165]    10 0.123     17 0.210 
## 3 (165,198]    51 0.630     68 0.840 
## 4 (198,231]     9 0.111     77 0.951 
## 5 otros         4 0.0494    81 1

Extrayendo información: estadística descriptiva con cuantitativas continuas

Scripts usados:

(haz click en las flechas para ver soluciones)

En la carpeta DATOS, en el fichero coches.csv, dispones de una tabla que contiene información de distintos tipos de vehículos. La información que contiene es:

  • name: nombre del vehículo
  • sports_car, suv, wagon, minivan, pickup, all_wheel, rear_wheel: variables lógicas, nos dicen si son de ese tipo o no.
  • msrp: precio de fábrica
  • dealer_cost: precio de coste
  • eng_size: tamaño del motor
  • ncyl: número de cilindros
  • city_mpg, hwy_mpg: consumo en distintos entornos
  • weight, wheel_base, length, width: distintas medidas de dimensión del vehículo

📝Ejercicio 1: genera una columna de tipo factor que aglutine las columnas binarias sports_car, suv, wagon, minivan, pickup en una sola que contenga el tipo (por ejemplo, si suv es TRUE, esa columna contendrá "suv")

  • Solución:
library(tidyverse)
coches <- read_csv("./DATOS/coches.csv")
coches <-
  coches %>%
  mutate(tipo =
           case_when(sports_car ~ "sports_car",
                     suv ~ "suv",
                     wagon ~ "wagon",
                     minivan ~ "minivan",
                     pickup ~ "pickup",
                     all_wheel ~ "all_wheel",
                     rear_wheel ~ "rear_wheel",
                     TRUE ~ "otros"),
         tipo = as_factor(tipo)) %>%
  select(-c(sports_car, suv, wagon, minivan, pickup))
fct_count(coches$tipo)
## # A tibble: 8 × 2
##   f              n
##   <fct>      <int>
## 1 otros        166
## 2 all_wheel     25
## 3 rear_wheel    54
## 4 sports_car    49
## 5 suv           60
## 6 wagon         30
## 7 minivan       20
## 8 pickup        24

 

📝Ejercicio 2: para ver si hay diferencia de consumo, ¿podrías calcular la media y desviación de city_mpg y hwy_mpg? Haz un diagrama que permita hacernos una idea de cómo se distribuye el consumo.

  • Solución:
coches %>% 
  summarise_at(vars(c("city_mpg", "hwy_mpg")),mean, na.rm = TRUE)
## # A tibble: 1 × 2
##   city_mpg hwy_mpg
##      <dbl>   <dbl>
## 1     20.1    26.9
coches %>% 
  summarise_at(vars(c("city_mpg", "hwy_mpg")),
               sd, na.rm = TRUE)
## # A tibble: 1 × 2
##   city_mpg hwy_mpg
##      <dbl>   <dbl>
## 1     5.21    5.70
# densidades
ggplot(coches %>%
         pivot_longer(cols = c("city_mpg", "hwy_mpg"),
                      names_to = "consumo",
                      values_to = "values") %>%
         drop_na(values),
       aes(x = values, fill = consumo)) +
  geom_density(alpha = 0.5) +
  scale_fill_discrete(labels = c("Ciudad", "Autopista"))
  labs(y = "densidad", x = "consumo (mpg)",
       fill = "Consumo")
## $y
## [1] "densidad"
## 
## $x
## [1] "consumo (mpg)"
## 
## $fill
## [1] "Consumo"
## 
## attr(,"class")
## [1] "labels"

 

📝Ejercicio 3: para ver si hay diferencia de consumo por tipo de coche, calcula la media de city_mpg y hwy_mpg para los distintos tipos de coche.

  • Solución:
coches %>% 
  group_by(tipo) %>% 
  summarise_at(vars(c("city_mpg", "hwy_mpg")),
               c(mean = mean, sd = sd), na.rm = TRUE)
## # A tibble: 8 × 5
##   tipo       city_mpg_mean hwy_mpg_mean city_mpg_sd hwy_mpg_sd
##   <fct>              <dbl>        <dbl>       <dbl>      <dbl>
## 1 otros               23.6         31.3        6.19       5.49
## 2 all_wheel           18.6         25.8        1.71       1.83
## 3 rear_wheel          18.0         25.5        1.48       2.35
## 4 sports_car          18.6         25.7        2.53       2.72
## 5 suv                 16.2         20.6        2.73       3.22
## 6 wagon               21.0         27.8        4.22       4.45
## 7 minivan             17.9         24.4        1.45       2.46
## 8 pickup              16.7         21.2        3.24       3.82
ggplot(coches %>% filter(tipo != "otros") %>%
         pivot_longer(cols = c("city_mpg", "hwy_mpg"),
                      names_to = "consumo",
                      values_to = "values") %>%
         drop_na(values), aes(x = values, fill = consumo)) + geom_density(alpha = 0.5) + facet_wrap( ~ tipo)

 

📝Ejercicio 4: a la vista de los resultados previos, seleccionar los 3 tipos de mayor consumo, filtra la tabla y representa la variable cyl con un gráfico de violín

  • Solución:
coches_filtro <- 
  coches %>% 
  filter(tipo %in%
           c("wagon", "all_wheel", "sports_car"))

library(ggthemes)
ggplot(coches_filtro,
       aes(x = tipo, y = ncyl,
           fill = tipo, color = tipo)) +
  geom_violin(alpha = 0.5, bw = 0.5) +
  scale_fill_tableau(labels = c("todo terreno", 
                                "deportivo",
                                "ranchera/familiar")) +
  scale_color_tableau() +
  guides(color = "none") +
  scale_x_discrete(labels = c("todo terreno", "deportivo",
                              "ranchera/familiar")) +
  labs(fill = "Tipos de coche",
       x = "Tipos de coche", y = "Cilindrada")

Resumiendo y relacionado datos

Scripts usados:

en construcción (cuarteto de anscombe)