class: center, middle .linea-superior[] .linea-inferior[] <img src="imagenes/logo_super_portada.png" width="180" /> # Curso Capacitación en R ## Sesión 4 ## Bases de datos 2 (tratamiento y análisis) ### Junio 2025 --- background-image: url("imagenes/background.png") background-size: contain; background-position: 50% 0% # Ejemplos de tratamiento y análisis -- Primero carguemos la librería `dplyr` y asignemos un objeto que contenga la base `starwars`. ``` r library(dplyr) df_starwars <- starwars ``` Pregunta: Filtrar la base por color de piel que sea `light` y color de ojos `brown`. Luego, ordenar (de mayor a menor) por `height` y `mass`. Finalmente sólo muestre las columnas: `name`,`height`, `mass`, `skin_color` y `eye_color`. ``` r df_starwars |> filter(skin_color == "light" & eye_color == "brown") |> arrange(desc(height), desc(mass)) |> select(name, height, mass, skin_color, eye_color) ``` ``` ## # A tibble: 7 × 5 ## name height mass skin_color eye_color ## <chr> <int> <dbl> <chr> <chr> ## 1 Raymus Antilles 188 79 light brown ## 2 Padmé Amidala 185 45 light brown ## 3 Biggs Darklighter 183 84 light brown ## 4 Dormé 165 NA light brown ## 5 Cordé 157 NA light brown ## 6 Leia Organa 150 49 light brown ## 7 Poe Dameron NA NA light brown ``` --- background-image: url("imagenes/background.png") background-size: contain; background-position: 50% 0% # Ejemplos de tratamiento y análisis El código de la slide anterior entrega el resultado de los procedimientos. Pero **NO** guarda los resultados en un objeto. Si se quiere guardar el objeto, este **DEBE** asignarse ya sea mediante dos opciones. -- La primera es **sobreescribir** el objeto `df_starwars`: ``` r df_starwars <- df_starwars |> filter(skin_color == "light" & eye_color == "brown") |> arrange(desc(height), desc(mass)) |> select(name, height, mass, skin_color, eye_color) ``` -- La segunda opción es generar **otro** objeto: ``` r df_starwars <- starwars starwars_piel_y_ojos <- df_starwars |> filter(skin_color == "light" & eye_color == "brown") |> arrange(desc(height), desc(mass)) |> select(name, height, mass, skin_color, eye_color) ``` **Recomendación:** siempre trate de mantener su base madre sin modificaciones. Si necesita limpiarla, cambiarla, etc., *eficientemente* genere nuevos objetos de acuerdo a sus necesidades. --- background-image: url("imagenes/background.png") background-size: contain; background-position: 50% 0% # Ejemplos de tratamiento y análisis Lidiemos con los **NA**. ``` r ejemplo <- c(1,2,NA,4) is.na(ejemplo) ``` ``` ## [1] FALSE FALSE TRUE FALSE ``` -- El código anterior nos permite saber si el vector contiene valores **NA**. Ahora, identifiquémoslos. ``` r which(is.na(ejemplo) == TRUE) ``` ``` ## [1] 3 ``` --- background-image: url("imagenes/background.png") background-size: contain; background-position: 50% 0% # Ejemplos de tratamiento y análisis Veámos que ocurre si lo utilizamos en una base de datos. ``` r is.na(starwars_piel_y_ojos) ``` ``` ## name height mass skin_color eye_color ## [1,] FALSE FALSE FALSE FALSE FALSE ## [2,] FALSE FALSE FALSE FALSE FALSE ## [3,] FALSE FALSE FALSE FALSE FALSE ## [4,] FALSE FALSE TRUE FALSE FALSE ## [5,] FALSE FALSE TRUE FALSE FALSE ## [6,] FALSE FALSE FALSE FALSE FALSE ## [7,] FALSE TRUE TRUE FALSE FALSE ``` -- ``` r which(is.na(starwars_piel_y_ojos) == TRUE) ``` ``` ## [1] 14 18 19 21 ``` No es muy útil. Mejor utilzarlo por columna. --- background-image: url("imagenes/background.png") background-size: contain; background-position: 50% 0% # Ejemplos de tratamiento y análisis ``` r which(is.na(starwars_piel_y_ojos$mass) == TRUE) ``` ``` ## [1] 4 5 7 ``` -- Confirmemos ``` r starwars_piel_y_ojos$mass[c(4,5,7)] ``` ``` ## [1] NA NA NA ``` -- También de forma rápida se puede conocer si alguna columna posee **al menos** un **NA**. ``` r anyNA(starwars_piel_y_ojos$mass) ``` ``` ## [1] TRUE ``` --- background-image: url("imagenes/background.png") background-size: contain; background-position: 50% 0% # Ejemplos de tratamiento y análisis Formas de reemplazar valores NA. -- Utilizando `if_else`: ``` r starwars_piel_y_ojos_sin_NA <- starwars_piel_y_ojos |> mutate(mass = if_else(is.na(mass) == TRUE, 0,mass)) starwars_piel_y_ojos_sin_NA ``` ``` ## # A tibble: 7 × 5 ## name height mass skin_color eye_color ## <chr> <int> <dbl> <chr> <chr> ## 1 Raymus Antilles 188 79 light brown ## 2 Padmé Amidala 185 45 light brown ## 3 Biggs Darklighter 183 84 light brown ## 4 Dormé 165 0 light brown ## 5 Cordé 157 0 light brown ## 6 Leia Organa 150 49 light brown ## 7 Poe Dameron NA 0 light brown ``` La función `if_else` funciona de la siguiente manera: *if_else(condition, true, false, missing = NULL,...)* --- background-image: url("imagenes/background.png") background-size: contain; background-position: 50% 0% # Ejemplos de tratamiento y análisis Si una determinada condición se activa cuando es `TRUE` no es necesario escribir `== TRUE`. Por ejemplo, para el caso anterior, podemos escribirlo de la siguiente forma: ``` r starwars_piel_y_ojos_sin_NA <- starwars_piel_y_ojos |> mutate(mass = if_else(is.na(mass), 0,mass)) # no necesité escribir == TRUE starwars_piel_y_ojos_sin_NA ``` ``` ## # A tibble: 7 × 5 ## name height mass skin_color eye_color ## <chr> <int> <dbl> <chr> <chr> ## 1 Raymus Antilles 188 79 light brown ## 2 Padmé Amidala 185 45 light brown ## 3 Biggs Darklighter 183 84 light brown ## 4 Dormé 165 0 light brown ## 5 Cordé 157 0 light brown ## 6 Leia Organa 150 49 light brown ## 7 Poe Dameron NA 0 light brown ``` --- background-image: url("imagenes/background.png") background-size: contain; background-position: 50% 0% # Ejemplos de tratamiento y análisis También se puede utilizar indexación en una columna en particular: ``` r starwars_piel_y_ojos$mass[is.na(starwars_piel_y_ojos$mass)] <- 0 starwars_piel_y_ojos ``` ``` ## # A tibble: 7 × 5 ## name height mass skin_color eye_color ## <chr> <int> <dbl> <chr> <chr> ## 1 Raymus Antilles 188 79 light brown ## 2 Padmé Amidala 185 45 light brown ## 3 Biggs Darklighter 183 84 light brown ## 4 Dormé 165 0 light brown ## 5 Cordé 157 0 light brown ## 6 Leia Organa 150 49 light brown ## 7 Poe Dameron NA 0 light brown ``` --- background-image: url("imagenes/background.png") background-size: contain; background-position: 50% 0% # Ejemplos de tratamiento y análisis O también en la base entera (miren la columna `height`): ``` r starwars_piel_y_ojos <- df_starwars |> # vuelvo a generar el objeto starwars_piel_y_ojos filter(skin_color == "light" & eye_color == "brown") |> arrange(desc(height), desc(mass)) |> select(name, height, mass, skin_color, eye_color) starwars_piel_y_ojos[is.na(starwars_piel_y_ojos)] <- 0 # asigno todos los NA a 0 starwars_piel_y_ojos # imprimo ``` ``` ## # A tibble: 7 × 5 ## name height mass skin_color eye_color ## <chr> <int> <dbl> <chr> <chr> ## 1 Raymus Antilles 188 79 light brown ## 2 Padmé Amidala 185 45 light brown ## 3 Biggs Darklighter 183 84 light brown ## 4 Dormé 165 0 light brown ## 5 Cordé 157 0 light brown ## 6 Leia Organa 150 49 light brown ## 7 Poe Dameron 0 0 light brown ``` --- background-image: url("imagenes/background.png") background-size: contain; background-position: 50% 0% # Ejemplos de tratamiento y análisis Deshagámosnos de las filas que contengan **NA**. ``` r starwars_piel_y_ojos_sin_NA <- df_starwars |> # vuelvo a generar el objeto starwars_piel_y_ojos filter(skin_color == "light" & eye_color == "brown") |> arrange(desc(height), desc(mass)) |> select(name, height, mass, skin_color, eye_color) |> filter(is.na(mass) == FALSE) starwars_piel_y_ojos_sin_NA ``` ``` ## # A tibble: 4 × 5 ## name height mass skin_color eye_color ## <chr> <int> <dbl> <chr> <chr> ## 1 Raymus Antilles 188 79 light brown ## 2 Padmé Amidala 185 45 light brown ## 3 Biggs Darklighter 183 84 light brown ## 4 Leia Organa 150 49 light brown ``` --- background-image: url("imagenes/background.png") background-size: contain; background-position: 50% 0% # Ejemplos de tratamiento y análisis Si en una condición quiero lo que sucede cuando esta **NO** se cumple, puedo utilizar el operador `!` y acortar la escritura de código. ``` r starwars_piel_y_ojos_sin_NA <- df_starwars |> # vuelvo a generar el objeto starwars_piel_y_ojos filter(skin_color == "light" & eye_color == "brown") |> arrange(desc(height), desc(mass)) |> select(name, height, mass, skin_color, eye_color) |> filter(!is.na(mass)) # operador ! starwars_piel_y_ojos_sin_NA ``` ``` ## # A tibble: 4 × 5 ## name height mass skin_color eye_color ## <chr> <int> <dbl> <chr> <chr> ## 1 Raymus Antilles 188 79 light brown ## 2 Padmé Amidala 185 45 light brown ## 3 Biggs Darklighter 183 84 light brown ## 4 Leia Organa 150 49 light brown ``` --- background-image: url("imagenes/background.png") background-size: contain; background-position: 50% 0% Volvamos a nuestra base con **NA**. ``` r starwars_piel_y_ojos <- df_starwars |> # vuelvo a generar el objeto starwars_piel_y_ojos filter(skin_color == "light" & eye_color == "brown") |> arrange(desc(height), desc(mass)) |> select(name, height, mass, skin_color, eye_color) ``` -- Hagamos lo siguiente: construyamos una base desde `starwars_piel_y_ojos` donde se cambie el valor de `mass` si el personaje es `Poe Dameron` por `\(75\)`, imprima el objeto. ``` r starwars_piel_y_ojos_poe <- starwars_piel_y_ojos |> mutate(mass = if_else(name == "Poe Dameron", 75, mass)) starwars_piel_y_ojos_poe ``` ``` ## # A tibble: 7 × 5 ## name height mass skin_color eye_color ## <chr> <int> <dbl> <chr> <chr> ## 1 Raymus Antilles 188 79 light brown ## 2 Padmé Amidala 185 45 light brown ## 3 Biggs Darklighter 183 84 light brown ## 4 Dormé 165 NA light brown ## 5 Cordé 157 NA light brown ## 6 Leia Organa 150 49 light brown ## 7 Poe Dameron NA 75 light brown ``` --- background-image: url("imagenes/background.png") background-size: contain; background-position: 50% 0% # Ejemplos de tratamiento y análisis Ahora, eliminemos las filas que tengan **NA** en las columnas `height` y `mass`. ``` r starwars_piel_y_ojos_poe_sin_na <- starwars_piel_y_ojos_poe |> filter(!is.na(mass) & !is.na(height)) starwars_piel_y_ojos_poe_sin_na ``` ``` ## # A tibble: 4 × 5 ## name height mass skin_color eye_color ## <chr> <int> <dbl> <chr> <chr> ## 1 Raymus Antilles 188 79 light brown ## 2 Padmé Amidala 185 45 light brown ## 3 Biggs Darklighter 183 84 light brown ## 4 Leia Organa 150 49 light brown ``` --- background-image: url("imagenes/background.png") background-size: contain; background-position: 50% 0% # Ejemplos de tratamiento y análisis Utilizar proposiciones lógicas complejas puede llevar a errores o confusiones en su código. Si usted no está 100% seguro de como funcionará una determinada condición es preferible descomponerla y hacerla de forma ordenada. ``` r starwars_piel_y_ojos_poe_sin_na <- starwars_piel_y_ojos_poe |> filter(!is.na(mass)) |> filter(!is.na(height)) starwars_piel_y_ojos_poe_sin_na ``` ``` ## # A tibble: 4 × 5 ## name height mass skin_color eye_color ## <chr> <int> <dbl> <chr> <chr> ## 1 Raymus Antilles 188 79 light brown ## 2 Padmé Amidala 185 45 light brown ## 3 Biggs Darklighter 183 84 light brown ## 4 Leia Organa 150 49 light brown ``` --- background-image: url("imagenes/background.png") background-size: contain; background-position: 50% 0% # Más herramientas de análisis Otra herramienta relevante para analizar información es la capacidad de **agrupamiento.** Esto se puede realizar mediante la función `group_by()`. ``` r df_starwars |> relocate(species) |> group_by(species) ``` ``` ## # A tibble: 87 × 14 ## # Groups: species [38] ## species name height mass hair_color skin_color eye_color birth_year sex ## <chr> <chr> <int> <dbl> <chr> <chr> <chr> <dbl> <chr> ## 1 Human Luke S… 172 77 blond fair blue 19 male ## 2 Droid C-3PO 167 75 <NA> gold yellow 112 none ## 3 Droid R2-D2 96 32 <NA> white, bl… red 33 none ## 4 Human Darth … 202 136 none white yellow 41.9 male ## 5 Human Leia O… 150 49 brown light brown 19 fema… ## 6 Human Owen L… 178 120 brown, gr… light blue 52 male ## 7 Human Beru W… 165 75 brown light blue 47 fema… ## 8 Droid R5-D4 97 32 <NA> white, red red NA none ## 9 Human Biggs … 183 84 black light brown 24 male ## 10 Human Obi-Wa… 182 77 auburn, w… fair blue-gray 57 male ## # ℹ 77 more rows ## # ℹ 5 more variables: gender <chr>, homeworld <chr>, films <list>, ## # vehicles <list>, starships <list> ``` --- background-image: url("imagenes/background.png") background-size: contain; background-position: 50% 0% # Más herramientas de análisis Por si sola la función `group_by()` no cambia los datos pero tiene un efecto en las operaciones subsiguientes. Una de las funciones más útiles al tener datos agrupados es `summarise()` o también `summarize()` (hacen lo mismo). Esta función crea un **nuevo** data frame con cada fila retornando una combinación de las variables agrupadas. Algunas funciones que se pueden utilizar son: `mean()`, `median()`,`sum()`, `sd()`, `min()`, `max()`, `n()`, `n_distinct()`, `any()`, `all()`, entre otras. --- background-image: url("imagenes/background.png") background-size: contain; background-position: 50% 0% # Más herramientas de análisis ``` r df_starwars |> group_by(species) |> summarise( cantidad_por_especie = n(), max_altura = max(height), min_masa = min(mass), alguno_proveniente_de_tatooine = any(homeworld == "Tatooine") ) ``` ``` ## # A tibble: 38 × 5 ## species cantidad_por_especie max_altura min_masa alguno_proveniente_de_ta…¹ ## <chr> <int> <int> <dbl> <lgl> ## 1 Aleena 1 79 15 FALSE ## 2 Besalisk 1 198 102 FALSE ## 3 Cerean 1 198 82 FALSE ## 4 Chagrian 1 196 NA FALSE ## 5 Clawdite 1 168 55 FALSE ## 6 Droid 6 NA NA TRUE ## 7 Dug 1 112 40 FALSE ## 8 Ewok 1 88 20 FALSE ## 9 Geonosian 1 183 80 FALSE ## 10 Gungan 3 224 NA FALSE ## # ℹ 28 more rows ## # ℹ abbreviated name: ¹alguno_proveniente_de_tatooine ``` --- background-image: url("imagenes/background.png") background-size: contain; background-position: 50% 0% # Más herramientas de análisis ``` r df_starwars |> group_by(species) |> summarise( suma_de_masas = sum(mass) ) |> filter(species == "Droid" | species == "Human") ``` ``` ## # A tibble: 2 × 2 ## species suma_de_masas ## <chr> <dbl> ## 1 Droid NA ## 2 Human NA ``` **¿Extraño o no?** --- background-image: url("imagenes/background.png") background-size: contain; background-position: 50% 0% # Más herramientas de análisis ``` r df_starwars |> group_by(species) |> summarise( suma_de_masas = sum(mass, na.rm = TRUE) ) |> filter(species == "Droid" | species == "Human") ``` ``` ## # A tibble: 2 × 2 ## species suma_de_masas ## <chr> <dbl> ## 1 Droid 279 ## 2 Human 1626. ``` --- background-image: url("imagenes/background.png") background-size: contain; background-position: 50% 0% # Más herramientas de análisis Muchas funciones poseen el argumento `na.rm = FALSE` que provoca que al utilizarlas no se quiten los valores `NA` al evaluarlas. Esto produce problemas ya que no se pueden calcular objetos de diferente naturaleza. ``` r ej_vector <- c(10,5,NA) sum(ej_vector) ``` ``` ## [1] NA ``` ``` r 10 + 5 + NA ``` ``` ## [1] NA ``` ``` r sum(ej_vector, na.rm = TRUE) ``` ``` ## [1] 15 ``` Al cambiar este argumento a `TRUE` se puede llevar a cabo el análisis sin considerar los `NA` y de esta forma calcular lo que se requiere.