Temas cubiertos: 1 (Introducción y conceptos básicos), 2 (Ingesta de datos), 3 (Limpieza y preprocesado)
Descripción: Este documento realiza la ingesta de
datos de Fórmula 1 desde 4 fuentes distintas (CSV, API REST, Excel,
JSON), explora su estructura y calidad, y aplica técnicas de limpieza
(NAs, duplicados, validación de tipos, normalización de textos). Los
datos limpios se guardan en datos/clean/.
Contexto en el ciclo de vida del dato: Este script cubre las fases de ingesta (recopilación de datos desde múltiples fuentes) y limpieza (asegurar la calidad antes de cualquier análisis).
install.packages(c("readxl", "jsonlite", "dplyr", "httr2", "ggplot2", "corrplot"))
library(readxl) # Lectura de archivos Excel
library(jsonlite) # Lectura de archivos JSON
library(dplyr) # Manipulación de datos
library(httr2) # Peticiones HTTP a la API
library(ggplot2) # Gráficos
Se utilizan diferentes librerías para gestionar la ingesta de datos desde múltiples fuentes y facilitar su limpieza y transformación.
# [PROPORCIONADO]
dir.create("datos/clean", recursive = TRUE, showWarnings = FALSE)
dir.create("datos/gold", recursive = TRUE, showWarnings = FALSE)
cat("Estructura de carpetas creada correctamente.\n")
## Estructura de carpetas creada correctamente.
Referencia: Tema 2 — Ingesta de datos
(read.csv)
Leer el archivo datos/raw/f1_resultados_historicos.csv
usando read.csv(). Revisar el separador de campos del
fichero (puede ser "," o ";"). Asignar el
resultado a df_resultados. Después, mostrar las primeras
filas con head() y la estructura con
str().
df_resultados <- read.csv("datos/raw/f1_resultados_historicos.csv", sep = ",")
head(df_resultados)
## season round race_name circuit_id
## 1 2022 4 Russian Grand Prix sochi
## 2 2015 1 Hungarian Grand Prix hungaroring
## 3 2017 12 Hungarian Grand Prix hungaroring
## 4 2018 4 Austrian Grand Prix red_bull_ring
## 5 2014 5 Spanish Grand Prix catalunya
## 6 2022 16 Austrian Grand Prix red_bull_ring
## circuit_name date driver_id driver_name
## 1 Sochi Autodrom 2022-06-01 tsunoda Yuki Tsunoda
## 2 Hungaroring 2015-10-18 lawson Liam Lawson
## 3 Hungaroring 2017-08-18 hulkenberg Nico Hülkenberg
## 4 Red Bull Ring 2018-10-23 sargeant Logan Sargeant
## 5 Circuit de Barcelona-Catalunya 2014-11-05 raikkonen Kimi Räikkönen
## 6 Red Bull Ring 2022-04-14 sargeant Logan Sargeant
## driver_nationality constructor grid position position_text points laps
## 1 Japanese Alfa Romeo 6 20 20 0 67
## 2 New Zealander Manor 1 4 4 12 65
## 3 German Manor 5 19 19 0 56
## 4 American Haas 5 NA R 0 20
## 5 Finnish Ferrari 10 NA R 0 5
## 6 American Alfa Romeo 2 2 2 18 58
## status fastest_lap_time fastest_lap_speed
## 1 +2 Laps 1:35.727 206.174
## 2 Finished 1:33.721 230.861
## 3 Finished NA
## 4 Hydraulics 1:23.903 231.109
## 5 Gearbox 1:17.230 234.613
## 6 Finished 1:18.126 232.487
str(df_resultados)
## 'data.frame': 3780 obs. of 18 variables:
## $ season : int 2022 2015 2017 2018 2014 2022 2014 2023 2015 2022 ...
## $ round : int 4 1 12 4 5 16 14 6 17 10 ...
## $ race_name : chr "Russian Grand Prix" "Hungarian Grand Prix" "Hungarian Grand Prix" "Austrian Grand Prix" ...
## $ circuit_id : chr "sochi" "hungaroring" "hungaroring" "red_bull_ring" ...
## $ circuit_name : chr "Sochi Autodrom" "Hungaroring" "Hungaroring" "Red Bull Ring" ...
## $ date : chr "2022-06-01" "2015-10-18" "2017-08-18" "2018-10-23" ...
## $ driver_id : chr "tsunoda" "lawson" "hulkenberg" "sargeant" ...
## $ driver_name : chr "Yuki Tsunoda" "Liam Lawson" "Nico Hülkenberg" "Logan Sargeant" ...
## $ driver_nationality: chr "Japanese" "New Zealander" "German" "American" ...
## $ constructor : chr "Alfa Romeo" "Manor" "Manor" "Haas" ...
## $ grid : int 6 1 5 5 10 2 9 13 8 9 ...
## $ position : int 20 4 19 NA NA 2 NA 5 5 13 ...
## $ position_text : chr "20" "4" "19" "R" ...
## $ points : int 0 12 0 0 0 18 0 10 10 0 ...
## $ laps : int 67 65 56 20 5 58 23 64 55 70 ...
## $ status : chr "+2 Laps" "Finished" "Finished" "Hydraulics" ...
## $ fastest_lap_time : chr "1:35.727" "1:33.721" "" "1:23.903" ...
## $ fastest_lap_speed : num 206 231 NA 231 235 ...
Se carga el dataset principal desde un archivo CSV que contiene los resultados históricos de Fórmula 1. Se inspecciona su estructura mediante head() y str() para comprender su contenido y tipos de datos.
Referencia: Tema 2 — Ingesta de datos (APIs)
La API devuelve datos en formato JSON. Se realizan dos llamadas: clasificación de pilotos y de constructores de la temporada 2024.
# [PROPORCIONADO] — Clasificación de pilotos 2024
tryCatch({
url_pilotos <- "https://api.jolpi.ca/ergast/f1/2024/driverStandings.json"
resp_pilotos <- request(url_pilotos) %>%
req_headers("Accept" = "application/json") %>%
req_perform()
json_pilotos <- resp_pilotos %>%
resp_body_json()
standings_pilotos <- json_pilotos$MRData$StandingsTable$StandingsLists[[1]]$DriverStandings
df_api_pilotos <- data.frame(
posicion = as.integer(sapply(standings_pilotos, function(x) x$position)),
puntos = as.numeric(sapply(standings_pilotos, function(x) x$points)),
victorias = as.integer(sapply(standings_pilotos, function(x) x$wins)),
driver_id = sapply(standings_pilotos, function(x) x$Driver$driverId),
nombre = sapply(standings_pilotos, function(x) x$Driver$givenName),
apellido = sapply(standings_pilotos, function(x) x$Driver$familyName),
nacionalidad = sapply(standings_pilotos, function(x) x$Driver$nationality),
constructor = sapply(standings_pilotos, function(x) x$Constructors[[1]]$name),
stringsAsFactors = FALSE
)
cat("Clasificación de pilotos 2024 descargada:", nrow(df_api_pilotos), "pilotos\n")
}, error = function(e) {
cat("Error al acceder a la API de pilotos:", e$message, "\n")
df_api_pilotos <<- data.frame()
})
## Clasificación de pilotos 2024 descargada: 24 pilotos
# [PROPORCIONADO] — Clasificación de constructores 2024
tryCatch({
url_constructores <- "https://api.jolpi.ca/ergast/f1/2024/constructorStandings.json"
resp_constructores <- request(url_constructores) %>%
req_headers("Accept" = "application/json") %>%
req_perform()
json_constructores <- resp_constructores %>%
resp_body_json()
standings_constructores <- json_constructores$MRData$StandingsTable$StandingsLists[[1]]$ConstructorStandings
df_api_constructores <- data.frame(
posicion = as.integer(sapply(standings_constructores, function(x) x$position)),
puntos = as.numeric(sapply(standings_constructores, function(x) x$points)),
victorias = as.integer(sapply(standings_constructores, function(x) x$wins)),
constructor_id = sapply(standings_constructores, function(x) x$Constructor$constructorId),
nombre_constructor = sapply(standings_constructores, function(x) x$Constructor$name),
nacionalidad = sapply(standings_constructores, function(x) x$Constructor$nationality),
stringsAsFactors = FALSE
)
cat("Clasificación de constructores 2024 descargada:", nrow(df_api_constructores), "equipos\n")
}, error = function(e) {
cat("Error al acceder a la API de constructores:", e$message, "\n")
df_api_constructores <<- data.frame()
})
## Clasificación de constructores 2024 descargada: 10 equipos
# [PROPORCIONADO] — Inspeccionar los datos recibidos de la API
cat("--- Datos de pilotos desde la API ---\n")
## --- Datos de pilotos desde la API ---
head(df_api_pilotos)
## posicion puntos victorias driver_id nombre apellido nacionalidad
## 1 1 437 9 max_verstappen Max Verstappen Dutch
## 2 2 374 4 norris Lando Norris British
## 3 3 356 3 leclerc Charles Leclerc Monegasque
## 4 4 292 2 piastri Oscar Piastri Australian
## 5 5 290 2 sainz Carlos Sainz Spanish
## 6 6 245 2 russell George Russell British
## constructor
## 1 Red Bull
## 2 McLaren
## 3 Ferrari
## 4 McLaren
## 5 Ferrari
## 6 Mercedes
cat("\n--- Datos de constructores desde la API ---\n")
##
## --- Datos de constructores desde la API ---
head(df_api_constructores)
## posicion puntos victorias constructor_id nombre_constructor nacionalidad
## 1 1 666 6 mclaren McLaren British
## 2 2 652 5 ferrari Ferrari Italian
## 3 3 589 9 red_bull Red Bull Austrian
## 4 4 468 4 mercedes Mercedes German
## 5 5 94 0 aston_martin Aston Martin British
## 6 6 65 0 alpine Alpine F1 Team French
Se realiza la ingesta de datos desde una API REST que proporciona información actualizada sobre la clasificación de pilotos y constructores. Esto permite enriquecer el análisis con datos recientes.
Referencia: Tema 2 — Ingesta de datos
(readxl)
Leer el archivo datos/raw/f1_equipos_presupuestos.xlsx.
Este archivo tiene dos hojas: “Equipos” y
“Presupuestos”. Usar read_excel() del paquete
readxl con el parámetro sheet para cada hoja.
Asignar cada hoja a una variable distinta: df_equipos y
df_presupuestos. Mostrar head() y
dim() de cada una.
df_equipos <- read_excel("datos/raw/f1_equipos_presupuestos.xlsx", sheet = "Equipos")
df_presupuestos <- read_excel("datos/raw/f1_equipos_presupuestos.xlsx", sheet = "Presupuestos")
head(df_equipos)
## # A tibble: 6 × 5
## nombre_equipo pais_sede anio_fundacion num_empleados director_equipo
## <chr> <chr> <dbl> <dbl> <chr>
## 1 Mercedes Germany 1954 1100 Toto Wolff
## 2 Ferrari Italy 1929 1200 Frédéric Vasseur
## 3 Red Bull Austria 2005 900 Christian Horner
## 4 McLaren United Kingdom 1963 850 Andrea Stella
## 5 Aston Martin United Kingdom 2021 700 Mike Krack
## 6 Alpine France 2021 750 Bruno Famin
dim(df_equipos)
## [1] 10 5
head(df_presupuestos)
## # A tibble: 6 × 5
## nombre_equipo temporada presupuesto_millones pct_desarrollo pct_personal
## <chr> <dbl> <dbl> <dbl> <dbl>
## 1 Mercedes 2019 135 47.9 32
## 2 Mercedes 2020 149. 36.8 36.5
## 3 Mercedes 2021 156. 49.9 28.4
## 4 Mercedes 2022 152 42 30.7
## 5 Mercedes 2023 159 48 39.9
## 6 Ferrari 2019 136. 39.1 29
dim(df_presupuestos)
## [1] 50 5
Se cargan las dos hojas del archivo Excel, que contienen información sobre los equipos y sus presupuestos, utilizando read_excel().
Referencia: Tema 2 — Ingesta de datos
(jsonlite)
Leer el archivo datos/raw/f1_pilotos_info.json usando
fromJSON() del paquete jsonlite. La función
devuelve una lista; acceder al elemento $pilotos para
obtener el dataframe. Asignar a df_pilotos_bio. Mostrar
head(), str() y dim().
json_data <- fromJSON("datos/raw/f1_pilotos_info.json")
df_pilotos_bio <- json_data$pilotos
head(df_pilotos_bio)
## code nombre apellido fecha_nacimiento nacionalidad equipo_actual
## 1 HAM Lewis Hamilton 1985-01-07 British Mercedes
## 2 VER Max Verstappen 1997-09-30 Dutch Red Bull
## 3 LEC Charles Leclerc 1997-10-16 Monegasque Ferrari
## 4 SAI Carlos Sainz 1994-09-01 Spanish Ferrari
## 5 NOR Lando Norris 1999-11-13 British McLaren
## 6 RUS George Russell 1998-02-15 British Mercedes
## estatura_cm peso_kg salario_anual_millones titulos_mundiales driver_id
## 1 174 73 55 7 hamilton
## 2 181 72 55 3 verstappen
## 3 180 70 24 0 leclerc
## 4 178 66 10 0 sainz
## 5 170 69 20 0 norris
## 6 185 70 8 0 russell
str(df_pilotos_bio)
## 'data.frame': 21 obs. of 11 variables:
## $ code : chr "HAM" "VER" "LEC" "SAI" ...
## $ nombre : chr "Lewis" "Max" "Charles" "Carlos" ...
## $ apellido : chr "Hamilton" "Verstappen" "Leclerc" "Sainz" ...
## $ fecha_nacimiento : chr "1985-01-07" "1997-09-30" "1997-10-16" "1994-09-01" ...
## $ nacionalidad : chr "British" "Dutch" "Monegasque" "Spanish" ...
## $ equipo_actual : chr "Mercedes" "Red Bull" "Ferrari" "Ferrari" ...
## $ estatura_cm : int 174 181 180 178 170 185 173 171 178 182 ...
## $ peso_kg : int 73 72 70 66 69 70 63 68 70 70 ...
## $ salario_anual_millones: num 55 55 24 10 20 8 10 20 5 10 ...
## $ titulos_mundiales : int 7 3 0 0 0 0 0 2 0 0 ...
## $ driver_id : chr "hamilton" "verstappen" "leclerc" "sainz" ...
dim(df_pilotos_bio)
## [1] 21 11
Se carga el archivo JSON con información biográfica de los pilotos y se transforma en un dataframe, facilitando su análisis.
La ingesta desde múltiples fuentes permite integrar información heterogénea en un único pipeline de datos.
Referencia: Tema 3 — Limpieza y preprocesado (exploración)
# [PROPORCIONADO] — Resumen de dimensiones
cat("========================================\n")
## ========================================
cat("RESUMEN DE DATASETS CARGADOS\n")
## RESUMEN DE DATASETS CARGADOS
cat("========================================\n")
## ========================================
cat("df_resultados (CSV):", dim(df_resultados)[1], "filas x", dim(df_resultados)[2], "columnas\n")
## df_resultados (CSV): 3780 filas x 18 columnas
cat("df_api_pilotos (API):", dim(df_api_pilotos)[1], "filas x", dim(df_api_pilotos)[2], "columnas\n")
## df_api_pilotos (API): 24 filas x 8 columnas
cat("df_api_constructores (API):", dim(df_api_constructores)[1], "filas x", dim(df_api_constructores)[2], "columnas\n")
## df_api_constructores (API): 10 filas x 6 columnas
cat("df_equipos (Excel):", dim(df_equipos)[1], "filas x", dim(df_equipos)[2], "columnas\n")
## df_equipos (Excel): 10 filas x 5 columnas
cat("df_presupuestos (Excel):", dim(df_presupuestos)[1], "filas x", dim(df_presupuestos)[2], "columnas\n")
## df_presupuestos (Excel): 50 filas x 5 columnas
cat("df_pilotos_bio (JSON):", dim(df_pilotos_bio)[1], "filas x", dim(df_pilotos_bio)[2], "columnas\n")
## df_pilotos_bio (JSON): 21 filas x 11 columnas
# [PROPORCIONADO] — Conteo de NAs y estadísticas del dataset principal
cat("--- Valores faltantes (NAs) en df_resultados ---\n")
## --- Valores faltantes (NAs) en df_resultados ---
print(colSums(is.na(df_resultados)))
## season round race_name circuit_id
## 0 0 0 0
## circuit_name date driver_id driver_name
## 0 0 0 0
## driver_nationality constructor grid position
## 0 0 0 1473
## position_text points laps status
## 0 27 0 0
## fastest_lap_time fastest_lap_speed
## 0 502
cat("\n--- Estadísticas descriptivas ---\n")
##
## --- Estadísticas descriptivas ---
summary(df_resultados)
## season round race_name circuit_id
## Min. :2014 Min. : 1.000 Length:3780 Length:3780
## 1st Qu.:2016 1st Qu.: 5.000 Class :character Class :character
## Median :2018 Median :10.000 Mode :character Mode :character
## Mean :2019 Mean : 9.918
## 3rd Qu.:2021 3rd Qu.:15.000
## Max. :2023 Max. :20.000
##
## circuit_name date driver_id driver_name
## Length:3780 Length:3780 Length:3780 Length:3780
## Class :character Class :character Class :character Class :character
## Mode :character Mode :character Mode :character Mode :character
##
##
##
##
## driver_nationality constructor grid position
## Length:3780 Length:3780 Min. : 1.00 Min. : 1.0
## Class :character Class :character 1st Qu.: 5.00 1st Qu.: 5.0
## Mode :character Mode :character Median :10.00 Median :10.0
## Mean :10.44 Mean :10.4
## 3rd Qu.:15.00 3rd Qu.:15.0
## Max. :20.00 Max. :20.0
## NA's :1473
## position_text points laps status
## Length:3780 Min. : 0.000 Min. : 5.00 Length:3780
## Class :character 1st Qu.: 0.000 1st Qu.:37.00 Class :character
## Mode :character Median : 0.000 Median :54.00 Mode :character
## Mean : 3.146 Mean :48.28
## 3rd Qu.: 4.000 3rd Qu.:62.00
## Max. :25.000 Max. :70.00
## NA's :27
## fastest_lap_time fastest_lap_speed
## Length:3780 Min. :185.0
## Class :character 1st Qu.:197.1
## Mode :character Median :209.6
## Mean :209.7
## 3rd Qu.:222.2
## Max. :235.0
## NA's :502
Se observa que las variables numéricas presentan diferentes rangos y distribuciones, lo que puede influir en el análisis posterior.
Referencia: Tema 3 — Limpieza y preprocesado
A) Tratamiento de NAs en
df_resultados:
points, grid, laps,
fastest_lap_speed): sustituir los NAs por la
media de la columna. PISTA:
mean(columna, na.rm = TRUE) y luego
df$col[is.na(df$col)] <- valor_media.status, fastest_lap_time): sustituir por el
valor más frecuente. PISTA: usar table() para ver
frecuencias.B) Detección y eliminación de duplicados:
duplicated() y
sum().df <- df[!duplicated(df), ].Mostrar el número de NAs y filas antes y después de cada operación.
# Exploración inicial del dataset
dim(df_resultados)
## [1] 3780 18
colSums(is.na(df_resultados))
## season round race_name circuit_id
## 0 0 0 0
## circuit_name date driver_id driver_name
## 0 0 0 0
## driver_nationality constructor grid position
## 0 0 0 1473
## position_text points laps status
## 0 27 0 0
## fastest_lap_time fastest_lap_speed
## 0 502
summary(df_resultados)
## season round race_name circuit_id
## Min. :2014 Min. : 1.000 Length:3780 Length:3780
## 1st Qu.:2016 1st Qu.: 5.000 Class :character Class :character
## Median :2018 Median :10.000 Mode :character Mode :character
## Mean :2019 Mean : 9.918
## 3rd Qu.:2021 3rd Qu.:15.000
## Max. :2023 Max. :20.000
##
## circuit_name date driver_id driver_name
## Length:3780 Length:3780 Length:3780 Length:3780
## Class :character Class :character Class :character Class :character
## Mode :character Mode :character Mode :character Mode :character
##
##
##
##
## driver_nationality constructor grid position
## Length:3780 Length:3780 Min. : 1.00 Min. : 1.0
## Class :character Class :character 1st Qu.: 5.00 1st Qu.: 5.0
## Mode :character Mode :character Median :10.00 Median :10.0
## Mean :10.44 Mean :10.4
## 3rd Qu.:15.00 3rd Qu.:15.0
## Max. :20.00 Max. :20.0
## NA's :1473
## position_text points laps status
## Length:3780 Min. : 0.000 Min. : 5.00 Length:3780
## Class :character 1st Qu.: 0.000 1st Qu.:37.00 Class :character
## Mode :character Median : 0.000 Median :54.00 Mode :character
## Mean : 3.146 Mean :48.28
## 3rd Qu.: 4.000 3rd Qu.:62.00
## Max. :25.000 Max. :70.00
## NA's :27
## fastest_lap_time fastest_lap_speed
## Length:3780 Min. :185.0
## Class :character 1st Qu.:197.1
## Mode :character Median :209.6
## Mean :209.7
## 3rd Qu.:222.2
## Max. :235.0
## NA's :502
# NAs antes
print("NAs antes:")
## [1] "NAs antes:"
sum(is.na(df_resultados))
## [1] 2002
# Sustituimos valores NA en variables numéricas por la media
# Imputación en points
media_points <- mean(df_resultados$points, na.rm = TRUE)
df_resultados$points[is.na(df_resultados$points)] <- media_points
# Imputación en otras variables numéricas
df_resultados$grid[is.na(df_resultados$grid)] <- mean(df_resultados$grid, na.rm = TRUE)
df_resultados$laps[is.na(df_resultados$laps)] <- mean(df_resultados$laps, na.rm = TRUE)
# NAs después
print("NAs después:")
## [1] "NAs después:"
sum(is.na(df_resultados))
## [1] 1975
# Duplicados antes
print("Duplicados antes:")
## [1] "Duplicados antes:"
sum(duplicated(df_resultados))
## [1] 20
df_resultados <- df_resultados[!duplicated(df_resultados), ]
# Duplicados después
print("Duplicados después:")
## [1] "Duplicados después:"
sum(duplicated(df_resultados))
## [1] 0
Los valores faltantes en variables numéricas se sustituyen por la media, con el objetivo de mantener la información sin introducir sesgos significativos.
Se detectan y eliminan registros duplicados para evitar distorsiones en el análisis.
Referencia: Tema 3 — Limpieza y preprocesado (validaciones)
A) Validación de tipos:
str(df_resultados).points, grid y
laps son numéricos (as.numeric()).constructor y driver_nationality
a factor (as.factor()).B) Normalización de textos:
constructor con
table() o unique().ifelse(), tolower() o
toupper().driver_nationality si es
necesario.#Validación de tipos
str(df_resultados)
## 'data.frame': 3760 obs. of 18 variables:
## $ season : int 2022 2015 2017 2018 2014 2022 2014 2023 2015 2022 ...
## $ round : int 4 1 12 4 5 16 14 6 17 10 ...
## $ race_name : chr "Russian Grand Prix" "Hungarian Grand Prix" "Hungarian Grand Prix" "Austrian Grand Prix" ...
## $ circuit_id : chr "sochi" "hungaroring" "hungaroring" "red_bull_ring" ...
## $ circuit_name : chr "Sochi Autodrom" "Hungaroring" "Hungaroring" "Red Bull Ring" ...
## $ date : chr "2022-06-01" "2015-10-18" "2017-08-18" "2018-10-23" ...
## $ driver_id : chr "tsunoda" "lawson" "hulkenberg" "sargeant" ...
## $ driver_name : chr "Yuki Tsunoda" "Liam Lawson" "Nico Hülkenberg" "Logan Sargeant" ...
## $ driver_nationality: chr "Japanese" "New Zealander" "German" "American" ...
## $ constructor : chr "Alfa Romeo" "Manor" "Manor" "Haas" ...
## $ grid : num 6 1 5 5 10 2 9 13 8 9 ...
## $ position : int 20 4 19 NA NA 2 NA 5 5 13 ...
## $ position_text : chr "20" "4" "19" "R" ...
## $ points : num 0 12 0 0 0 18 0 10 10 0 ...
## $ laps : num 67 65 56 20 5 58 23 64 55 70 ...
## $ status : chr "+2 Laps" "Finished" "Finished" "Hydraulics" ...
## $ fastest_lap_time : chr "1:35.727" "1:33.721" "" "1:23.903" ...
## $ fastest_lap_speed : num 206 231 NA 231 235 ...
df_resultados$points <- as.numeric(df_resultados$points)
df_resultados$grid <- as.numeric(df_resultados$grid)
df_resultados$laps <- as.numeric(df_resultados$laps)
df_resultados$constructor <- as.factor(df_resultados$constructor)
df_resultados$driver_nationality <- as.factor(df_resultados$driver_nationality)
#Normalización de tipos
df_resultados$constructor <- tolower(df_resultados$constructor)
df_resultados$constructor <- ifelse(df_resultados$constructor == "mercedes", "Mercedes", df_resultados$constructor)
df_resultados$constructor <- as.factor(df_resultados$constructor)
table(df_resultados$constructor)
##
## alfa romeo alphatauri alpine aston martin ferrari force india
## 226 226 114 114 376 150
## haas lotus manor mclaren Mercedes racing point
## 226 150 150 376 376 112
## red bull renault sauber toro rosso williams
## 376 112 150 150 376
Se validan y ajustan los tipos de datos para asegurar la coherencia del dataset, convirtiendo variables a formato numérico o categórico según corresponda.
Se normalizan los valores de variables categóricas para evitar inconsistencias en los datos.
# [PROPORCIONADO]
saveRDS(df_resultados, "datos/clean/resultados_clean.rds")
saveRDS(df_api_pilotos, "datos/clean/api_pilotos_clean.rds")
saveRDS(df_api_constructores, "datos/clean/api_constructores_clean.rds")
saveRDS(df_equipos, "datos/clean/equipos_clean.rds")
saveRDS(df_presupuestos, "datos/clean/presupuestos_clean.rds")
saveRDS(df_pilotos_bio, "datos/clean/pilotos_bio_clean.rds")
cat("\n========================================\n")
##
## ========================================
cat("Todos los datasets limpios guardados en datos/clean/\n")
## Todos los datasets limpios guardados en datos/clean/
cat("Script 1 completado con éxito.\n")
## Script 1 completado con éxito.
cat("========================================\n")
## ========================================
Este script representa las primeras fases del pipeline de datos, asegurando que la información está limpia y preparada para su transformación y análisis posterior. Este proceso asegura que los datos estén preparados para las fases posteriores del pipeline, evitando errores y mejorando la calidad del análisis.
Explica brevemente qué es el ciclo de vida del dato y en qué fase se encuentra la ingesta de datos. ¿Qué riesgos existen si se omite la fase de limpieza?
Tu respuesta aquí (5-10 líneas):
El ciclo de vida del dato describe las fases por las que pasa la información desde su captura hasta su uso en la toma de decisiones. La ingesta se sitúa en la fase inicial, donde se recopilan los datos desde distintas fuentes.
Si se omite la fase de limpieza, los datos pueden contener errores, valores inconsistentes o duplicados, lo que afectaría negativamente a la calidad del análisis y a las decisiones basadas en dichos datos.
La limpieza garantiza la calidad del dato y es clave para evitar errores que se propaguen a lo largo del pipeline.
¿Qué diferencia hay entre sustituir un valor faltante (NA) por la media y eliminarlo directamente? ¿En qué situaciones usarías cada estrategia?
Tu respuesta aquí (5-10 líneas):
Sustituir un valor faltante por la media permite mantener el tamaño del dataset y evitar la pérdida de información, aunque puede reducir la variabilidad de los datos.
Por otro lado, eliminar registros con valores faltantes puede ser más adecuado cuando el número de NAs es pequeño o cuando estos afectan a variables críticas. La elección depende del contexto y del impacto que tenga cada estrategia en el análisis.
Eliminar datos puede introducir sesgo si los valores faltantes no son aleatorios.