# Instala una sola vez (si aún no lo tienes)
install.packages("tidyverse")
install.packages("naniar") # para explorar datos faltantes2 Importación y exploración de datos
- R2. Importar y manipular bases de datos en R.
En este capítulo damos el salto desde datos que escribimos a mano hacia datos reales que viven en archivos. Trabajaremos con el ecosistema tidyverse, una colección de paquetes diseñados para el análisis de datos.
library(tidyverse)
library(naniar)2.1 Importar un archivo CSV
La función read_csv() lee un archivo de valores separados por comas y lo guarda como un data frame (técnicamente, un tibble). En este ejemplo usamos un dataset de los animes mejor rankeados.
anime <- read_csv("data/anime.csv")Si trabajas dentro de un Proyecto de RStudio, las rutas se escriben relativas a la carpeta del proyecto. Así "data/..." funcionará en cualquier computador, sin necesidad de setwd().
2.2 Explorar la estructura de los datos
Antes de analizar, siempre conviene mirar los datos. Estas funciones son tus herramientas básicas de exploración:
str(anime) # estructura: tipo de cada columnaspc_tbl_ [2,000 × 19] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
$ anime_id : num [1:2000] 25833 1237 9202 30868 34784 ...
$ name : chr [1:2000] "Zephyr" "One Piece: Oounabara ni Hirake! Dekkai Dekkai Chichi no Yume!" "Seikon no Qwaser: Jotei no Shouzou" "Ajin Part 1: Shoudou" ...
$ english_name: chr [1:2000] NA "One Piece: Open Upon the Great Sea! A Father's Huge, HUGE Dream!" "The Qwaser of Stigmata: Portrait of the Empress" "Ajin: Demi-Human Movie 1: Compel" ...
$ score : num [1:2000] 5.87 7.18 6.37 7.42 7.19 7.6 5.7 6.61 8.46 6.9 ...
$ genres : chr [1:2000] "Drama" "Action, Adventure, Fantasy" "Action, Ecchi" "Action, Horror, Mystery, Supernatural" ...
$ themes : chr [1:2000] "Music" NA "Gore, Harem, School, Super Power" "Gore" ...
$ demographics: chr [1:2000] NA "Shounen" "Seinen" "Seinen" ...
$ type : chr [1:2000] "Special" "TV Special" "OVA" "Movie" ...
$ episodes : num [1:2000] 1 1 1 1 1 25 23 1 12 1 ...
$ premiered : chr [1:2000] NA NA NA NA ...
$ studios : chr [1:2000] "Satelight" "Toei Animation" "Hoods Entertainment" "Polygon Pictures" ...
$ source : chr [1:2000] "Unknown" "Manga" "Manga" "Manga" ...
$ duration : chr [1:2000] "26 min" "46 min" "23 min" "1 hr 44 min" ...
$ rating : chr [1:2000] "PG-13 - Teens 13 or older" "PG-13 - Teens 13 or older" "R+ - Mild Nudity" "R - 17+ (violence & profanity)" ...
$ rank : num [1:2000] 10577 3478 7847 2283 3402 ...
$ popularity : num [1:2000] 10969 4010 4352 3423 5422 ...
$ favorites : num [1:2000] 7 17 16 49 7 ...
$ scored_by : num [1:2000] 317 16732 11696 17295 6080 ...
$ members : num [1:2000] 2643 34805 29381 47229 17401 ...
- attr(*, "spec")=
.. cols(
.. anime_id = col_double(),
.. name = col_character(),
.. english_name = col_character(),
.. score = col_double(),
.. genres = col_character(),
.. themes = col_character(),
.. demographics = col_character(),
.. type = col_character(),
.. episodes = col_double(),
.. premiered = col_character(),
.. studios = col_character(),
.. source = col_character(),
.. duration = col_character(),
.. rating = col_character(),
.. rank = col_double(),
.. popularity = col_double(),
.. favorites = col_double(),
.. scored_by = col_double(),
.. members = col_double()
.. )
- attr(*, "problems")=<pointer: 0x74aff8340>
glimpse(anime) # versión más ordenada de str() (tidyverse)Rows: 2,000
Columns: 19
$ anime_id <dbl> 25833, 1237, 9202, 30868, 34784, 10278, 7808, 32338, 4451…
$ name <chr> "Zephyr", "One Piece: Oounabara ni Hirake! Dekkai Dekkai …
$ english_name <chr> NA, "One Piece: Open Upon the Great Sea! A Father's Huge,…
$ score <dbl> 5.87, 7.18, 6.37, 7.42, 7.19, 7.60, 5.70, 6.61, 8.46, 6.9…
$ genres <chr> "Drama", "Action, Adventure, Fantasy", "Action, Ecchi", "…
$ themes <chr> "Music", NA, "Gore, Harem, School, Super Power", "Gore", …
$ demographics <chr> NA, "Shounen", "Seinen", "Seinen", "Shounen", NA, NA, NA,…
$ type <chr> "Special", "TV Special", "OVA", "Movie", "Special", "TV",…
$ episodes <dbl> 1, 1, 1, 1, 1, 25, 23, 1, 12, 1, 13, 2, 4, 52, NA, 1, 1, …
$ premiered <chr> NA, NA, NA, NA, NA, "summer 2011", "spring 1980", NA, "fa…
$ studios <chr> "Satelight", "Toei Animation", "Hoods Entertainment", "Po…
$ source <chr> "Unknown", "Manga", "Manga", "Manga", "Manga", "Game", "N…
$ duration <chr> "26 min", "46 min", "23 min", "1 hr 44 min", "15 min", "2…
$ rating <chr> "PG-13 - Teens 13 or older", "PG-13 - Teens 13 or older",…
$ rank <dbl> 10577, 3478, 7847, 2283, 3402, 1580, 11396, NA, 160, NA, …
$ popularity <dbl> 10969, 4010, 4352, 3423, 5422, 1592, 13587, 9487, 62, 138…
$ favorites <dbl> 7, 17, 16, 49, 7, 1690, 3, 7, 49992, 1, 18088, 2, 28, 0, …
$ scored_by <dbl> 317, 16732, 11696, 17295, 6080, 55143, 340, 1831, 958426,…
$ members <dbl> 2643, 34805, 29381, 47229, 17401, 156465, 1199, 4159, 169…
summary(anime) # resumen estadístico anime_id name english_name score
Min. : 5 Length :2000 Length :2000 Min. :5.580
1st Qu.: 5762 N.unique :2000 N.unique :1114 1st Qu.:6.130
Median :28330 N.blank : 0 N.blank : 0 Median :6.565
Mean :25745 Min.nchar: 2 Min.nchar: 3 Mean :6.680
3rd Qu.:40843 Max.nchar: 105 Max.nchar: 116 3rd Qu.:7.170
Max. :60811 NAs : 883 Max. :9.060
genres themes demographics type
Length :2000 Length :2000 Length :2000 Length :2000
N.unique : 325 N.unique : 331 N.unique : 6 N.unique : 9
N.blank : 0 N.blank : 0 N.blank : 0 N.blank : 0
Min.nchar: 5 Min.nchar: 4 Min.nchar: 4 Min.nchar: 2
Max.nchar: 63 Max.nchar: 58 Max.nchar: 13 Max.nchar: 10
NAs : 204 NAs : 661 NAs :1387
episodes premiered studios source
Min. : 1.0 Length :2000 Length :2000 Length :2000
1st Qu.: 1.0 N.unique : 182 N.unique : 504 N.unique : 16
Median : 3.0 N.blank : 0 N.blank : 0 N.blank : 0
Mean : 13.6 Min.nchar: 9 Min.nchar: 3 Min.nchar: 4
3rd Qu.: 13.0 Max.nchar: 11 Max.nchar: 54 Max.nchar: 12
Max. :1274.0 NAs :1345 NAs : 292
NAs :15
duration rating rank popularity
Length :2000 Length :2000 Min. : 4 Min. : 6
N.unique : 193 N.unique : 6 1st Qu.: 3027 1st Qu.: 3648
N.blank : 0 N.blank : 0 Median : 6104 Median : 7691
Min.nchar: 4 Min.nchar: 11 Mean : 5960 Mean : 8276
Max.nchar: 18 Max.nchar: 30 3rd Qu.: 8951 3rd Qu.:12497
NAs : 8 Max. :11861 Max. :21551
NAs :376
favorites scored_by members
Min. : 0.0 Min. : 103.0 Min. : 200
1st Qu.: 2.0 1st Qu.: 556.5 1st Qu.: 1649
Median : 12.0 Median : 2675.0 Median : 7245
Mean : 795.9 Mean : 37890.2 Mean : 74734
3rd Qu.: 106.0 3rd Qu.: 17303.5 3rd Qu.: 42306
Max. :110803.0 Max. :2206556.0 Max. :3175177
nrow(anime) # número de filas (observaciones)[1] 2000
ncol(anime) # número de columnas (variables)[1] 19
names(anime) # nombres de las columnas [1] "anime_id" "name" "english_name" "score" "genres"
[6] "themes" "demographics" "type" "episodes" "premiered"
[11] "studios" "source" "duration" "rating" "rank"
[16] "popularity" "favorites" "scored_by" "members"
Para revisar el tipo de una columna específica usamos class():
class(anime$episodes)[1] "numeric"
class(anime$rank)[1] "numeric"
2.3 Detectar datos faltantes (NA)
Los valores faltantes se representan con NA. Ignorarlos puede arruinar un análisis, así que el primer paso es cuantificarlos:
n_miss(anime) # total de NA (paquete naniar)[1] 5171
sum(is.na(anime)) # forma equivalente en R base[1] 5171
vis_miss(anime) # visualiza el patrón de NA por columna
sum(is.na(anime$episodes)) # NA en una columna específica[1] 15
Para quedarnos solo con las filas sin NA en una columna, filtramos con la negación lógica !:
anime_sin_na <- anime %>%
filter(!is.na(episodes))2.4 El operador pipe %>%
El símbolo %>% (pipe) encadena operaciones: toma el resultado de la izquierda y lo entrega como primer argumento de la función de la derecha. Se lee como “y luego”. Es la columna vertebral del tidyverse.
También existe el pipe nativo de R |>, que funciona de forma muy similar. Verás ambos a lo largo del curso.
2.5 Conteos y frecuencias
count() cuenta cuántas observaciones hay por categoría; con sort = TRUE las ordena de mayor a menor:
anime %>% count(type, sort = TRUE) # ¿cuántos hay de cada tipo?anime %>% count(source, sort = TRUE) # ¿de qué fuente provienen?table(anime$rating) # alternativa en R base
G - All Ages PG - Children
415 111
PG-13 - Teens 13 or older R - 17+ (violence & profanity)
996 190
R+ - Mild Nudity Rx - Hentai
131 149
# Cantidad de valores únicos en una columna
anime %>% distinct(source) %>% nrow()[1] 16
2.6 Ordenar y seleccionar
arrange() ordena filas; desc() invierte el orden (de mayor a menor). select() elige columnas y head(n) muestra las primeras n filas:
# Top 10 animes por puntaje
anime %>%
arrange(desc(score)) %>%
head(10) %>%
select(name, score, type, episodes)filter() permite combinar varias condiciones separándolas con comas (que funcionan como un “Y” lógico):
# Los 5 animes de tipo "Movie" con más miembros
anime %>%
filter(type == "Movie") %>%
arrange(desc(members)) %>%
head(5) %>%
select(name, members, score)Ejercicios
Usando el dataset anime:
- Usa tres funciones distintas para explorar su estructura.
- ¿Cuántas filas y columnas tiene?
- Obtén los nombres de todas las columnas.
- ¿Cuántos valores faltantes hay en total? ¿Y en la columna
episodes? - Crea
anime_sin_naconservando solo filas dondeepisodesno seaNA. - ¿Cuál es la fuente (
source) más frecuente? - Encuentra los 10 animes con más favoritos (
favorites). ¿Coinciden con los mejor puntuados?