Manipulación de datos con R

Autor/a
Afiliación

Javier Emmanuel Anguiano Pita

Universidad de Guadalajara

Fecha de modificación

27 de diciembre de 2024

Este documento es parte del curso Introducción a la programación en R para Ciencias Sociales

Introducción

En esta práctica trabajaremos con el conjunto de datos IMDB Top 250 dataset french. Utiliza el siguiente código para descargarla en tu computadora:

download.file(
  url = "https://eanguianopita.github.io/docs/curso_R/Datos/01_imdb-top250-french.csv", 
  destfile = "IMDB250_french.csv")

Ejercicio 0

Importa el archivo que acabamos de descargar usando la función read.csv(). Verifica la ubicación de tu directorio de trabajo y modificalo si es necesario.

IMDB <- read.csv("IMDB250_french.csv", encoding = "UTF-8")

Ejercicio 1

Inspecciona el contenido de la base de datos IMDB usando la función glimpse() contenida en la librería tidyverse. Esta función puede ser muy útil para tener una visión panorámica sobre la estructura de nuestros datos.

library(tidyverse)
glimpse(IMDB)

Ejercicio 2

Identifica al menos 4 problemas en la base de datos que deberían resolverse para poder hacer un ejercicio de análisis. Nota que hasta este momento no necesariamente sabemos como resolver los problemas.

Rows: 250
Columns: 13
$ X              <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, …
$ Name           <chr> "Shoah", "Home", "Untouchable", "Le Trou", "The Man Who…
$ Rank           <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, …
$ Year           <chr> "-1985", "(I) (2009)", "-2011", "-1960", "-1987", "-194…
$ Type           <chr> "PG", "U", "15", "A", "", "A", "15", "15", "A", "U", "U…
$ Duration       <chr> "566 min", "118 min", "112 min", "131 min", "30 min", "…
$ Genre          <chr> "Documentary, History, War", "Documentary", "Biography,…
$ Rating         <dbl> 8.7, 8.5, 8.5, 8.5, 8.5, 8.3, 8.3, 8.3, 8.2, 8.2, 8.2, …
$ MetaScore      <int> 99, 47, 57, NA, NA, 96, 69, 80, NA, NA, NA, 86, 99, NA,…
$ Desc           <chr> "Claude Lanzmann's epic documentary recounts the story …
$ Director_Stars <chr> "Director:\nClaude Lanzmann\n                 | \n    S…
$ Votes          <chr> "9,984", "", "", "", "", "", "", "", "", "", "", "", ""…
$ Gross          <chr> "$0.02M", "", "", "", "", "", "", "", "", "", "", "", "…

Ejercicio 2.1

La variable Year no es de tipo numeric y contien algunos caractéres que no deberían estar ahí p.ej. “-”, “()”, “(I)”, etc. Aquí vamos a corregir ese problema:

IMDB$Year[1:50]  # Visualicemos más datos

IMDB2 <- IMDB %>% 
  # Arreglamos la variable Year
  mutate(Year = if_else(str_length(Year) == 5, # Si el formato es "-YYYY",
                        str_sub(Year, 2, 5),  # Extraemos posición 2-5
                        str_sub(Year, 6, 9)), # EOC es "(I) (YYYY)"
         Year = as.numeric(Year))

IMDB2$Year

Existen otras alternativas para corregir los problemas con la variable Year. Por ejemplo, podemos usar expresiones regulares para describir patrones en las cadenas de texto ( strings ). Revisa la cheatsheet sobre el uso de expresiones regulares usando el paquete {stringr} en este enlace.

Solución con expresiones regulares

Puedes consultar una cheatsheet sobre el uso de expresiones regulares con el paquete stringr en este Enlace.

rm(IMDB2)

IMDB2 <- IMDB %>% 
  mutate(Year = as.numeric(gsub("[^0-9]+","", Year)))

IMDB2$Year

Explicación detallada

El código anterior gsub("[^0-9]+","", Year) utiliza la función gsub() para buscar un patrón y realizar una sustitución en la cadena de texto guardada en la variable Year.

Argumentos de la función gsub():

gsub(patrón a buscar, reemplazo, nombre_variable)
  • "[^0-9]+": Este es un patrón de expresión regular que significa “cualquier cosa que no sea un número del 0 al 9. Nota que el + significa que puede haber uno o más de estos caractéres no numéricos.
  • El símbolo ^ dentro de los corchetes indica una negación.
  • +: Significa “uno o más de estos caracteres no numéricos”. Esto asegura que se eliminen grupos consecutivos de caracteres no numéricos.
  • "": Esto significa que estamos reemplazando los caracteres que coinciden con el patrón anterior (cualquier cosa que no sea un número), con una cadena vacía. En otras palabras, los eliminamos.

Ejercicio 2.2

La variable Type o clasificación de la película contiene valores que no están codificados como perdidos sino que son espacios en blanco generados usando "".

Para codificar correctamente los datos perdidos podemos usar el siguiente código:

# Reemplazar los valores perdidos con NA en variable Type

IMDB2 <- IMDB2 %>%
  mutate(Type = if_else(Type == "", NA_character_, Type))

Supongamos que además de codificar las variables queremos descartar las observaciones con valores perdidos i.e., NA. Para tal propósito podemos complementar el código anterior con las siguientes líneas:

IMDB2 <- IMDB %>%
  mutate(Type = if_else(Type == "", NA_character_, Type)) %>% 
  filter(!is.na(Type))

Ejercicio 2.3

La variable Genre no esta representada de forma útil. Debemos convertirla en una variable categórica o dummy. Nota que la forma en que se clasifican las películas se traslapa (i.e. "Drama, Mystery, Thriller").

Para solucionar este problema, primero vamos a convertir la variable Genre en una variable categórica. Para tal propósito, vamos a usar la función case_when() para clasificar el contenido de la variable Genre en categorías generales:

library(dplyr)
library(stringr)

# Veamos cuatas categorías únicas hay en  la variable Genre
unique(IMDB$Genre)

# Recodificamos la clasificación en categorías generales

IMDB2 <- IMDB2 %>%
  mutate(Genre_Cat = case_when(
    str_detect(Genre, "Action") ~ "Action",  # ~ Asigna el valor
    str_detect(Genre, "Comedy") ~ "Comedy",
    str_detect(Genre, "Drama") ~ "Drama",
    str_detect(Genre, "Horror") ~ "Horror",
    str_detect(Genre, "Sci-Fi") ~ "Sci-Fi",
    str_detect(Genre, "Thriller") ~ "Thriller",
    str_detect(Genre, "Animation") ~ "Animation",
    TRUE ~ "Other" # Todas las otras categorías
  ),
  Genre_Cat = factor(Genre_Cat)
  )

unique(IMDB2$Genre_Cat)  #Revisamos el resultado
str(IMDB2$Genre_Cat)  # ¿Qué tipo de datos tenemos? 

Ejercicio 2.4

La variable Director_Stars está almacenando realmente dos variables Director y Stars. Asimismo, contiene los strings Director: y Stars:. Debemos separar esta variable en dos nuevas columnas en nuestra base de datos y eliminar las palabras sobrantes.

Para este propósito podemos usar la función separte_wider_delim(). Esta funcion requiere que definamos primero que símbolo se está usando para delimitar las dos variables en cuestión. (Nota: el separador es : |. La expresion \n es un caracter que implica un salto de línea. )

# Observamos las características de la variable

IMDB2$Director_Stars[1:10]

# Limpiamos y separamos los datos
IMDB2 <- IMDB2 %>%
  mutate(
    # Removemos \n (separador de líneas)
    Director_Stars = gsub("\n", " ", Director_Stars) 
    # Removemos el espacio excesivo
    %>% str_squish()
    )    %>%
  # Separamos las columnas usando como delimitador el símbolo "|"
  separate_wider_delim(Director_Stars, delim = " | ", names = c("Director", "Stars")) %>%
  mutate(
    # Rmovemos las etiquetas de las columnas
    Director = str_remove(Director, "Director:\\s*"),
    Stars = str_remove(Stars, "Stars:\\s*")  
    )
  # Usamos \\s* como comodín de espacios en blanco
# Resultado
View(IMDB2)

Ejercicio 2.5

La variable Duration mide la duración de cada película en minutos. Sin embargo, nota que los datos contienen el valor numérico y el string min en la misma celda. Necesitamos generar una nueva variable numerica que nos permita ordenar las películas de acuerdo a su duración en orden ascendente.

IMDB2 <- IMDB2 %>%
  mutate(
    duration_num = str_remove(Duration, " min") %>% # Remove " min"
      as.numeric()  # Convert the remaining string to numeric
  ) %>% 
  arrange(duration_num) # Usa arrange(-var) para orden descendente

Ejercicio 3

En este ejercicio vamos a crear una tabla que nos muestre, por cada década, los promedio de la variable Rating. Para tal propósito, primero vamos a crear una nueva variable denominada decade usando condicionales. Después, vamos a calcular el promedio de la variable Rating agrupando los valores usando group_by() para cada década. Asegurate de que la tabla ordene los valores promedio de rating en orden descendente.

Solución:

 IMDB2 %>%
# Creamos una variable que indique la década
mutate(decade = case_when(
Year %in% c(1950:1959) ~ "50s",
Year %in% c(1960:1969) ~ "60s",
Year %in% c(1970:1979) ~ "70s",
Year %in% c(1980:1989) ~ "80s",
Year %in% c(1990:1999) ~ "90s",
Year %in% c(2000:2009) ~ "2000s",
Year %in% c(2010:2019) ~ "2010s",
Year %in% c(2019:2029) ~ "2020s",
.default = "40s or older")) %>%
  
# Creamos una tabla con los valores del rating por década
group_by(decade) %>%
summarise(avg_rating = mean(Rating)) %>%
arrange(-avg_rating)  # Ordenamos de mayor a menor 

Fin de la práctica guíada