Leer datos del mundo real con readr
Por qué readr y no R base
R base tiene read.csv() desde siempre. El tidyverse incluye read_csv() de readr. La diferencia no es marketing, son comportamientos por defecto distintos que importan:
read.csv() (base) |
read_csv() (readr) |
|
|---|---|---|
| Velocidad | Lenta | ~10× más rápida |
| Strings | Convierte a factor por defecto (sorpresa clásica antes de R 4.0) |
Las mantiene como character |
| Tipo de retorno | data.frame |
tibble (impresión más limpia) |
| Mensajes | Silencioso (no avisa de problemas) | Reporta tipos detectados y problemas |
na.strings |
Por defecto solo "" y NA |
Reconoce más representaciones (NA, "", etc.) |
Usa read_csv() por defecto. La excepción es data.table::fread() cuando trabajas con archivos enormes (varios GB) donde la velocidad de lectura es el cuello de botella.
read_csv(), read_csv2(), read_delim()
library(readr)
# CSV separado por comas (estándar internacional)
ventas <- read_csv("data/ventas.csv")
# CSV separado por punto-y-coma (común en Europa)
ventas <- read_csv2("data/ventas.csv")
# Cualquier otro delimitador (tab, pipe, etc.)
log <- read_delim("data/log.txt", delim = "|")
# TSV (tab-separated)
genes <- read_tsv("data/genes.tsv")read_csv2 importa más de lo que parece en datos europeos: por convención, en países donde la coma es el separador decimal (España, Francia, Alemania), los CSV usan punto-y-coma como separador de columnas para evitar ambigüedad. Si abres el archivo en un editor de texto y ves ;, usa read_csv2.
Lo que readr adivina (y a veces se equivoca)
Cuando ejecutas read_csv("data/ventas.csv"), verás un mensaje como:
Rows: 10000 Columns: 5
── Column specification ─────────────────────────
Delimiter: ","
chr (2): region, vendedor
dbl (2): unidades, precio_unidad
date (1): fecha
readr ha leído las primeras filas (por defecto 1000) y ha deducido el tipo de cada columna. Esto es muy útil pero no es magia. Tres puntos a tener claros:
- Es una estimación, no una verdad. Si las primeras 1000 filas de una columna parecen números pero la fila 1500 tiene texto,
readrla tipará comodbly ese texto se convertirá enNAcon un warning. Léelos. - Las fechas se detectan solo en formato ISO (
yyyy-mm-dd). Si tu archivo tiene01/03/2024,readrlo dejará comocharacter. Hay que decírselo. - El mensaje de tipos lo puedes silenciar con
show_col_types = FALSE, pero al principio es información valiosa. No lo silencies por reflejo.
Tipos por columna: cómo darle pistas
Cuando readr se equivoca o cuando quieres ser explícito, usa col_types:
ventas <- read_csv(
"data/ventas.csv",
col_types = cols(
fecha = col_date(format = "%d/%m/%Y"),
region = col_character(),
vendedor = col_character(),
unidades = col_integer(),
precio_unidad = col_double(),
activo = col_logical()
)
)Especificadores frecuentes:
col_character(),col_integer(),col_double(),col_logical(), los básicos.col_factor(levels = c("A", "B")): factor con niveles controlados.col_date(format = "%d/%m/%Y"): fechas con formato custom.col_datetime(format = "..."): fechas con hora.col_skip(): ignorar la columna (útil cuando hay columnas basura).
Atajo cuando hay muchas columnas y solo quieres especificar algunas:
ventas <- read_csv(
"data/ventas.csv",
col_types = cols(
fecha = col_date(format = "%d/%m/%Y"),
.default = col_guess()
)
).default = col_guess() deja que readr adivine el resto. Es el patrón sano: corrige lo que sabes que es problemático, deja el resto al detector automático.
El locale: cuando los decimales son comas
Datos generados en hojas de cálculo europeas suelen venir con:
- Decimales con coma (
1.234,56para “mil doscientos treinta y cuatro coma cincuenta y seis”). - Separador de miles con punto.
- Fechas en formato
dd/mm/yyyy.
readr interpreta esto con un objeto locale():
ventas <- read_csv2(
"data/ventas.csv",
locale = locale(
decimal_mark = ",",
grouping_mark = ".",
date_format = "%d/%m/%Y"
)
)Esto le dice: “los números pueden tener coma como decimal y punto como agrupador. Las fechas vienen en formato europeo”. Sin este locale(), los números como "1.234,56" se interpretan como string (porque tienen comas) y readr los deja como character.
Para datos en formato anglosajón (decimal con punto, fecha ISO), el locale() por defecto está bien y no necesitas tocarlo.
Trampas habituales
- CSVs que pasaron por Excel. Excel a veces “corrige” datos al guardar: convierte códigos como
"0123"en número (perdiendo el cero inicial), reinterpreta fechas según el locale del sistema, exporta números con coma decimal aunque originalmente fueran con punto. Antes de leer un CSV que pasó por Excel, ábrelo en un editor de texto plano (VS Code, Notepad++) y comprueba qué hay realmente dentro. - Encoding raro. Si tienes acentos que se ven como
ñen vez deñ, el archivo está en UTF-8 pero R lo lee como latin1 (o al revés).read_csv("file.csv", locale = locale(encoding = "latin1"))resuelve la mayoría de los casos. - El BOM al principio del archivo. Algunos CSV UTF-8 generados en Windows empiezan con un BOM (byte-order-mark, tres bytes invisibles). Hace que la primera columna se llame algo como
"region"en vez de"region".readrdesde la versión 2.0 maneja el BOM automáticamente, pero si ves nombres raros en la primera columna, ya sabes la causa.
En la siguiente entrega
Ya tienes los datos en un tibble. El primer verbo que aplicarás casi siempre es filter(): quedarte solo con las filas que te interesan. Es el siguiente tutorial, y tiene más profundidad de la que parece, especialmente con los NA.