7  Importación de datos

7.1 Introducción

Trabajar con datos proporcionados por paquetes de R es una excelente manera de aprender herramientas de ciencia de datos, pero desea aplicar lo que ha aprendido a sus propios datos en algún momento. En este capítulo, aprenderá los aspectos básicos de la lectura de archivos de datos en R.

Específicamente, este capítulo se centrará en la lectura de archivos rectangulares de texto sin formato. Comenzaremos con consejos prácticos para manejar características como nombres de columnas, tipos y datos faltantes. Luego aprenderá a leer datos de varios archivos a la vez y a escribir datos de R en un archivo. Finalmente, aprenderá cómo crear data frames en R.

7.1.1 Requisitos previos

En este capítulo, aprenderá a cargar archivos planos en R con el paquete readr, que forma parte del núcleo tidyverse.

7.2 Lectura de datos de un archivo

Para comenzar, nos centraremos en el tipo de archivo de datos más rectangular más común: CSV, que es la abreviatura de valores separados por comas. Así es como se ve un archivo CSV simple. La primera fila, comúnmente llamada fila de encabezado, proporciona los nombres de las columnas y las seis filas siguientes proporcionan los datos. Las columnas están separadas, también conocidas como delimitadas, por comas.

Student ID,Full Name,favourite.food,mealPlan,AGE
1,Sunil Huffmann,Strawberry yoghurt,Lunch only,4
2,Barclay Lynn,French fries,Lunch only,5
3,Jayendra Lyne,N/A,Breakfast and lunch,7
4,Leon Rossini,Anchovies,Lunch only,
5,Chidiegwu Dunkel,Pizza,Breakfast and lunch,five
6,Güvenç Attila,Ice cream,Lunch only,6

Tabla 7.1 muestra una representación de los mismos datos que una tabla.

Tabla 7.1: Datos del archivo students.csv como una tabla.
Student ID Full Name favourite.food mealPlan AGE
1 Sunil Huffmann Strawberry yoghurt Lunch only 4
2 Barclay Lynn French fries Lunch only 5
3 Jayendra Lyne N/A Breakfast and lunch 7
4 Leon Rossini Anchovies Lunch only NA
5 Chidiegwu Dunkel Pizza Breakfast and lunch five
6 Güvenç Attila Ice cream Lunch only 6

Podemos leer este archivo en R usando read_csv(). El primer argumento es el más importante: la ruta al archivo. Puede pensar en la ruta como la dirección del archivo: el archivo se llama students.csv y vive en la carpeta data.

students <- read_csv("data/students.csv")
#> Rows: 6 Columns: 5
#> ── Column specification ─────────────────────────────────────────────────────
#> Delimiter: ","
#> chr (4): Full Name, favourite.food, mealPlan, AGE
#> dbl (1): Student ID
#> 
#> ℹ Use `spec()` to retrieve the full column specification for this data.
#> ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

El código anterior funcionará si tiene el archivo students.csv en una carpeta data en su proyecto. Puede descargar el archivo students.csv desde https://pos.it/r4ds-students-csv o puede leerlo directamente desde esa URL con:

students <- read_csv("https://pos.it/r4ds-students-csv")

Cuando ejecuta read_csv(), imprime un mensaje que le indica el número de filas y columnas de datos, el delimitador que se usó y las especificaciones de las columnas (nombres de columnas organizados por el tipo de datos que contiene la columna). También imprime información sobre cómo recuperar la especificación de columna completa y cómo silenciar este mensaje. Este mensaje es una parte integral de readr, y regresaremos a él en Sección 7.3.

7.2.1 Consejo practico

Una vez que lee los datos, el primer paso generalmente consiste en transformarlos de alguna manera para que sea más fácil trabajar con ellos en el resto de su análisis. Echemos otro vistazo a los datos de students con eso en mente.

students
#> # A tibble: 6 × 5
#>   `Student ID` `Full Name`      favourite.food     mealPlan            AGE  
#>          <dbl> <chr>            <chr>              <chr>               <chr>
#> 1            1 Sunil Huffmann   Strawberry yoghurt Lunch only          4    
#> 2            2 Barclay Lynn     French fries       Lunch only          5    
#> 3            3 Jayendra Lyne    N/A                Breakfast and lunch 7    
#> 4            4 Leon Rossini     Anchovies          Lunch only          <NA> 
#> 5            5 Chidiegwu Dunkel Pizza              Breakfast and lunch five 
#> 6            6 Güvenç Attila    Ice cream          Lunch only          6

En la columna favourite.food, hay un montón de artículos de comida, y luego la cadena de caracteres N/A, que debería haber sido un NA real que R reconocerá como “no disponible”. Esto es algo que podemos abordar usando el argumento na. Por defecto read_csv() solo reconoce cadenas vacías ("") como NAs, y queremos que también reconozca la cadena de caracteres "N/A.

students <- read_csv("data/students.csv", na = c("N/A", ""))

students
#> # A tibble: 6 × 5
#>   `Student ID` `Full Name`      favourite.food     mealPlan            AGE  
#>          <dbl> <chr>            <chr>              <chr>               <chr>
#> 1            1 Sunil Huffmann   Strawberry yoghurt Lunch only          4    
#> 2            2 Barclay Lynn     French fries       Lunch only          5    
#> 3            3 Jayendra Lyne    <NA>               Breakfast and lunch 7    
#> 4            4 Leon Rossini     Anchovies          Lunch only          <NA> 
#> 5            5 Chidiegwu Dunkel Pizza              Breakfast and lunch five 
#> 6            6 Güvenç Attila    Ice cream          Lunch only          6

También puede notar que las columnas Student ID y Full Name están rodeadas de acentos graves. Eso es porque contienen espacios, rompiendo las reglas usuales de R para nombres de variables; son nombres no sintácticos. Para hacer referencia a estas variables, debe rodearlas con acentos graves, `:

students |> 
  rename(
    student_id = `Student ID`,
    full_name = `Full Name`
  )
#> # A tibble: 6 × 5
#>   student_id full_name        favourite.food     mealPlan            AGE  
#>        <dbl> <chr>            <chr>              <chr>               <chr>
#> 1          1 Sunil Huffmann   Strawberry yoghurt Lunch only          4    
#> 2          2 Barclay Lynn     French fries       Lunch only          5    
#> 3          3 Jayendra Lyne    <NA>               Breakfast and lunch 7    
#> 4          4 Leon Rossini     Anchovies          Lunch only          <NA> 
#> 5          5 Chidiegwu Dunkel Pizza              Breakfast and lunch five 
#> 6          6 Güvenç Attila    Ice cream          Lunch only          6

Un enfoque alternativo es usar janitor::clean_names() para usar algunas heurísticas para convertirlos todos en un caso de serpiente a la vez 1.

students |> janitor::clean_names()
#> # A tibble: 6 × 5
#>   student_id full_name        favourite_food     meal_plan           age  
#>        <dbl> <chr>            <chr>              <chr>               <chr>
#> 1          1 Sunil Huffmann   Strawberry yoghurt Lunch only          4    
#> 2          2 Barclay Lynn     French fries       Lunch only          5    
#> 3          3 Jayendra Lyne    <NA>               Breakfast and lunch 7    
#> 4          4 Leon Rossini     Anchovies          Lunch only          <NA> 
#> 5          5 Chidiegwu Dunkel Pizza              Breakfast and lunch five 
#> 6          6 Güvenç Attila    Ice cream          Lunch only          6

Otra tarea común después de leer datos es considerar tipos de variables. Por ejemplo, meal_plan es una variable categórica con un conjunto conocido de valores posibles, que en R debería representarse como un factor:

students |>
  janitor::clean_names() |>
  mutate(meal_plan = factor(meal_plan))
#> # A tibble: 6 × 5
#>   student_id full_name        favourite_food     meal_plan           age  
#>        <dbl> <chr>            <chr>              <fct>               <chr>
#> 1          1 Sunil Huffmann   Strawberry yoghurt Lunch only          4    
#> 2          2 Barclay Lynn     French fries       Lunch only          5    
#> 3          3 Jayendra Lyne    <NA>               Breakfast and lunch 7    
#> 4          4 Leon Rossini     Anchovies          Lunch only          <NA> 
#> 5          5 Chidiegwu Dunkel Pizza              Breakfast and lunch five 
#> 6          6 Güvenç Attila    Ice cream          Lunch only          6

Tenga en cuenta que los valores en la variable meal_plan se han mantenido igual, pero el tipo de variable indicado debajo del nombre de la variable ha cambiado de carácter (<chr>) a factor (<fct>). Aprenderá más sobre los factores en Capítulo 16.

Antes de analizar estos datos, probablemente querrá arreglar las columna age. Actualmente, age es una variable de carácter porque una de las observaciones se escribe como five en lugar de un 5 numérico. Discutimos los detalles para solucionar este problema en Capítulo 20.

students <- students |>
  janitor::clean_names() |>
  mutate(
    meal_plan = factor(meal_plan),
    age = parse_number(if_else(age == "five", "5", age))
  )

students
#> # A tibble: 6 × 5
#>   student_id full_name        favourite_food     meal_plan             age
#>        <dbl> <chr>            <chr>              <fct>               <dbl>
#> 1          1 Sunil Huffmann   Strawberry yoghurt Lunch only              4
#> 2          2 Barclay Lynn     French fries       Lunch only              5
#> 3          3 Jayendra Lyne    <NA>               Breakfast and lunch     7
#> 4          4 Leon Rossini     Anchovies          Lunch only             NA
#> 5          5 Chidiegwu Dunkel Pizza              Breakfast and lunch     5
#> 6          6 Güvenç Attila    Ice cream          Lunch only              6

Una nueva función aquí es if_else(), que tiene tres argumentos. El primer argumento test debe ser un vector lógico. El resultado contendrá el valor del segundo argumento, yes, cuando test es TRUE, y el valor del tercer argumento, no, cuando es FALSE. Aquí decimos que si age es la cadena de caracteres "five", conviértala en "5", y si no, déjela como age. Aprenderá más sobre if_else() y los vectores lógicos en Capítulo 12.

7.2.2 Otros argumentos

Hay un par de otros argumentos importantes que debemos mencionar, y serán más fáciles de demostrar si primero le mostramos un truco útil: read_csv() puede leer archivos CSV que ha creado en una cadena:

read_csv(
  "a,b,c
  1,2,3
  4,5,6"
)
#> # A tibble: 2 × 3
#>       a     b     c
#>   <dbl> <dbl> <dbl>
#> 1     1     2     3
#> 2     4     5     6

Por lo general, read_csv() usa la primera línea de los datos para los nombres de las columnas, lo cual es una convención muy común. Pero no es raro que se incluyan algunas líneas de metadatos en la parte superior del archivo. Puede usar skip = n para omitir las primeras n líneas o usar comment = "#" para descartar todas las líneas que comienzan con (por ejemplo) #:

read_csv(
  "La primera línea de metadatos
  La segunda línea de metadatos
  x,y,z
  1,2,3",
  skip = 2
)
#> # A tibble: 1 × 3
#>       x     y     z
#>   <dbl> <dbl> <dbl>
#> 1     1     2     3

read_csv(
  "# Un comentario que quiero saltar
  x,y,z
  1,2,3",
  comment = "#"
)
#> # A tibble: 1 × 3
#>       x     y     z
#>   <dbl> <dbl> <dbl>
#> 1     1     2     3

En otros casos, es posible que los datos no tengan nombres de columna. Puedes usar col_names = FALSE para decirle a read_csv() que no trate la primera fila como encabezados y, en su lugar, etiquétalos secuencialmente desde X1 a Xn:

read_csv(
  "1,2,3
  4,5,6",
  col_names = FALSE
)
#> # A tibble: 2 × 3
#>      X1    X2    X3
#>   <dbl> <dbl> <dbl>
#> 1     1     2     3
#> 2     4     5     6

Alternativamente, puede pasar col_names un vector de caracteres que se usará como los nombres de las columnas:

read_csv(
  "1,2,3
  4,5,6",
  col_names = c("x", "y", "z")
)
#> # A tibble: 2 × 3
#>       x     y     z
#>   <dbl> <dbl> <dbl>
#> 1     1     2     3
#> 2     4     5     6

Estos argumentos son todo lo que necesita saber para leer la mayoría de los archivos CSV que encontrará en la práctica. (Por lo demás, deberá inspeccionar cuidadosamente su archivo .csv y leer la documentación de los muchos otros argumentos de read_csv()).

7.2.3 Otros tipos de archivos

Una vez que haya dominado read_csv(), usar las otras funciones de readr es sencillo; es solo una cuestión de saber qué función alcanzar:

  • read_csv2() lee archivos separados por punto y coma. Estos usan ; en lugar de , para separar campos y son comunes en países que usan , como marcador decimal.

  • read_tsv() lee archivos delimitados por tabuladores.

  • read_delim() lee archivos con cualquier delimitador, intentando adivinar automáticamente el delimitador si no lo especificas.

  • read_fwf() lee archivos de ancho fijo. Puede especificar campos por sus anchos con fwf_widths() o por sus posiciones con fwf_positions().

  • read_table() lee una variación común de archivos de ancho fijo donde las columnas están separadas por espacios en blanco.

  • read_log() lee archivos de registro de estilo Apache.

7.2.4 Ejercicios

  1. ¿Qué función usaría para leer un archivo donde los campos se separaron con “|”?

  2. Aparte de file, skip y comment, ¿qué otros argumentos tienen en común read_csv() y read_tsv()?

  3. ¿Cuáles son los argumentos más importantes para read_fwf()?

  4. A veces, las cadenas de un archivo CSV contienen comas. Para evitar que causen problemas, deben estar rodeados por un carácter de comillas, como " o '. Por defecto, read_csv() asume que el carácter de comillas será ". Para leer el siguiente texto en un data frame, ¿qué argumento para read_csv() necesita especificar?

    "x,y\n1,'a,b'"
  5. Identifique qué está mal con cada uno de los siguientes archivos CSV en línea. ¿Qué sucede cuando ejecutas el código?

    read_csv("a,b\n1,2,3\n4,5,6")
    read_csv("a,b,c\n1,2\n1,2,3,4")
    read_csv("a,b\n\"1")
    read_csv("a,b\n1,2\na,b")
    read_csv("a;b\n1;3")
  6. Practique referirse a nombres no sintácticos en el siguiente marco de datos:

    1. Extrayendo la variable llamada 1.
    2. Trazar un diagrama de dispersión de 1 frente a 2. C. Crear una nueva columna llamada 3, que es 2 dividido por 1.
    3. Cambiar el nombre de las columnas a uno, dos y tres.
    annoying <- tibble(
      `1` = 1:10,
      `2` = `1` * 2 + rnorm(length(`1`))
    )

7.3 Controlar tipos de columna

Un archivo CSV no contiene ninguna información sobre el tipo de cada variable (es decir, si es un número lógico, una cadena, etc.), por lo que readr intentará adivinar el tipo. Esta sección describe cómo funciona el proceso de adivinación, cómo resolver algunos problemas comunes que hacen que falle y, si es necesario, cómo proporcionar los tipos de columna usted mismo. Finalmente, mencionaremos algunas estrategias generales que son útiles si readr está fallando catastróficamente y necesita obtener más información sobre la estructura de su archivo.

7.3.1 Adivinar tipos

readr usa una heurística para averiguar los tipos de columna. Para cada columna, extrae los valores de 1000[^data-import-2] filas espaciadas uniformemente desde la primera fila hasta la última, ignorando los valores faltantes. Luego trabaja a través de las siguientes preguntas:

[^importación de datos-2]: puede anular el valor predeterminado de 1000 con el argumento guess_max.

  • ¿Contiene solo F, T, FALSE o TRUE (ignorando mayúsculas y minúsculas)? Si es así, es una lógica.
  • ¿Contiene solo números (por ejemplo, 1, -4.5, 5e6, Inf)? Si es así, es un número.
  • ¿Coincide con el estándar ISO8601? Si es así, es una fecha o fecha-hora. (Volveremos a las fechas y horas con más detalle en Sección 17.2).
  • De lo contrario, debe ser una cadena.

Puedes ver ese comportamiento en acción en este sencillo ejemplo:

read_csv("
  logico,numerico,fecha,cadena
  TRUE,1,2021-01-15,abc
  false,4.5,2021-02-15,def
  T,Inf,2021-02-16,ghi"
)
#> Rows: 3 Columns: 4
#> ── Column specification ─────────────────────────────────────────────────────
#> Delimiter: ","
#> chr  (1): cadena
#> dbl  (1): numerico
#> lgl  (1): logico
#> date (1): fecha
#> 
#> ℹ Use `spec()` to retrieve the full column specification for this data.
#> ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
#> # A tibble: 3 × 4
#>   logico numerico fecha      cadena
#>   <lgl>     <dbl> <date>     <chr> 
#> 1 TRUE        1   2021-01-15 abc   
#> 2 FALSE       4.5 2021-02-15 def   
#> 3 TRUE      Inf   2021-02-16 ghi

Esta heurística funciona bien si tiene un conjunto de datos limpio, pero en la vida real encontrará una selección de fallas extrañas y hermosas.

7.3.2 Valores faltantes, tipos de columnas y problemas

La forma más común en que falla la detección de columnas es que una columna contiene valores inesperados y obtiene una columna de caracteres en lugar de un tipo más específico. Una de las causas más comunes de esto es un valor faltante, registrado usando algo diferente al NA que espera stringr.

Tome este simple archivo CSV de 1 columna como ejemplo:

csv <- "
  x
  10
  .
  20
  30"

Si lo leemos sin argumentos adicionales, x se convierte en una columna de caracteres:

df <- read_csv(csv)
#> Rows: 4 Columns: 1
#> ── Column specification ─────────────────────────────────────────────────────
#> Delimiter: ","
#> chr (1): x
#> 
#> ℹ Use `spec()` to retrieve the full column specification for this data.
#> ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

En este caso muy pequeño, puede ver fácilmente el valor faltante .. Pero, ¿qué sucede si tiene miles de filas con solo unos pocos valores faltantes representados por . salpicados entre ellos? Un enfoque es decirle a readr que x es una columna numérica y luego ver dónde falla. Puede hacerlo con el argumento col_types, que toma una lista con nombre:

df <- read_csv(csv, col_types = list(x = col_double()))
#> Warning: One or more parsing issues, call `problems()` on your data frame for
#> details, e.g.:
#>   dat <- vroom(...)
#>   problems(dat)

Ahora read_csv() informa que hubo un problema y nos dice que podemos averiguar más con problems():

problems(df)
#> # A tibble: 1 × 5
#>     row   col expected actual file                            
#>   <int> <int> <chr>    <chr>  <chr>                           
#> 1     3     1 a double .      /tmp/RtmpgRPOkp/file52c6788a96fa

Esto nos dice que hubo un problema en la fila 3, columna 1 donde readr esperaba un doble pero obtuvo un .. Eso sugiere que este conjunto de datos usa . para valores faltantes. Entonces establecemos na = ".", la adivinación automática tiene éxito, dándonos la columna numérica que queremos:

df <- read_csv(csv, na = ".")
#> Rows: 4 Columns: 1
#> ── Column specification ─────────────────────────────────────────────────────
#> Delimiter: ","
#> dbl (1): x
#> 
#> ℹ Use `spec()` to retrieve the full column specification for this data.
#> ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

7.3.3 Tipos de columna

readr proporciona un total de nueve tipos de columnas para su uso:

  • col_logical() y col_double() leen números lógicos y reales. Son relativamente raramente necesarios (excepto como se indicó anteriormente), ya que readr generalmente los adivinará por usted.
  • col_integer() lee números enteros. Distinguimos enteros y dobles en este libro porque son funcionalmente equivalentes, pero leer enteros explícitamente puede ser útil en ocasiones porque ocupan la mitad de la memoria de los dobles.
  • col_character() lee cadenas de texto. Esto puede ser útil para especificar explícitamente cuando tiene una columna que es un identificador numérico, es decir, una larga serie de dígitos que identifica un objeto pero no tiene sentido aplicarle operaciones matemáticas. Los ejemplos incluyen números de teléfono, números de seguro social, números de tarjetas de crédito, etc.
  • col_factor(), col_date() y col_datetime() crean factores, fechas y fecha-hora respectivamente; aprenderá más sobre ellos cuando lleguemos a esos tipos de datos en Capítulo 16 y Capítulo 17.
  • col_number() es un analizador numérico permisivo que ignorará los componentes no numéricos y es particularmente útil para las monedas. Aprenderá más al respecto en Capítulo 13.
  • col_skip() salta una columna por lo que no se incluye en el resultado.

También es posible anular la columna predeterminada cambiando de list() a cols():

csv <- "
x,y,z
1,2,3"

read_csv(csv, col_types = cols(.default = col_character()))
#> # A tibble: 1 × 3
#>   x     y     z    
#>   <chr> <chr> <chr>
#> 1 1     2     3

Otro ayudante útil es cols_only() que leerá solo las columnas que especifique:

read_csv(
  "x,y,z
  1,2,3",
  col_types = cols_only(x = col_character())
)
#> # A tibble: 1 × 1
#>   x    
#>   <chr>
#> 1 1

7.4 Lectura de datos de varios archivos

A veces, sus datos se dividen en varios archivos en lugar de estar contenidos en un solo archivo. Por ejemplo, puede tener datos de ventas de varios meses, con los datos de cada mes en un archivo separado: 01-sales.csv para enero, 02-sales.csv para febrero y 03-sales.csv para marzo. Con read_csv() puedes leer estos datos a la vez y apilarlos uno encima del otro en un solo data frame.

sales_files <- c("data/01-sales.csv", "data/02-sales.csv", "data/03-sales.csv")
read_csv(sales_files, id = "file")
#> Rows: 19 Columns: 6
#> ── Column specification ─────────────────────────────────────────────────────
#> Delimiter: ","
#> chr (1): month
#> dbl (4): year, brand, item, n
#> 
#> ℹ Use `spec()` to retrieve the full column specification for this data.
#> ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
#> # A tibble: 19 × 6
#>   file              month    year brand  item     n
#>   <chr>             <chr>   <dbl> <dbl> <dbl> <dbl>
#> 1 data/01-sales.csv January  2019     1  1234     3
#> 2 data/01-sales.csv January  2019     1  8721     9
#> 3 data/01-sales.csv January  2019     1  1822     2
#> 4 data/01-sales.csv January  2019     2  3333     1
#> 5 data/01-sales.csv January  2019     2  2156     9
#> 6 data/01-sales.csv January  2019     2  3987     6
#> # ℹ 13 more rows

Con el parámetro id adicional, hemos agregado una nueva columna llamada file al data frame resultante que identifica el archivo del que provienen los datos. Esto es especialmente útil en circunstancias en las que los archivos que está leyendo no tienen una columna de identificación que pueda ayudarlo a rastrear las observaciones hasta sus fuentes originales.

Si tiene muchos archivos que desea leer, puede resultar engorroso escribir sus nombres en una lista. En su lugar, puede usar la función básica list.files() para encontrar los archivos haciendo coincidir un patrón en los nombres de los archivos. Aprenderá más sobre estos patrones en Capítulo 15.

sales_files <- list.files("data", pattern = "sales\\.csv$", full.names = TRUE)
sales_files
#> [1] "data/01-sales.csv" "data/02-sales.csv" "data/03-sales.csv"

7.5 Escribir en un archivo

readr también viene con dos funciones útiles para volver a escribir datos en el disco: write_csv() y write_tsv(). Ambas funciones aumentan las posibilidades de que el archivo de salida se vuelva a leer correctamente mediante el uso de la codificación UTF-8 estándar para cadenas y el formato ISO8601 para fecha y hora.

Los argumentos más importantes son x (el marco de datos para guardar) y file (la ubicación para guardarlo). También puede especificar cómo se escriben los valores faltantes con na y si desea agregar a un archivo existente.

write_csv(students, "students.csv")

Ahora volvamos a leer ese archivo csv. Tenga en cuenta que la información de tipo se pierde cuando guarda en csv:

students
#> # A tibble: 6 × 5
#>   student_id full_name        favourite_food     meal_plan             age
#>        <dbl> <chr>            <chr>              <fct>               <dbl>
#> 1          1 Sunil Huffmann   Strawberry yoghurt Lunch only              4
#> 2          2 Barclay Lynn     French fries       Lunch only              5
#> 3          3 Jayendra Lyne    <NA>               Breakfast and lunch     7
#> 4          4 Leon Rossini     Anchovies          Lunch only             NA
#> 5          5 Chidiegwu Dunkel Pizza              Breakfast and lunch     5
#> 6          6 Güvenç Attila    Ice cream          Lunch only              6
write_csv(students, "students-2.csv")
read_csv("students-2.csv")
#> # A tibble: 6 × 5
#>   student_id full_name        favourite_food     meal_plan             age
#>        <dbl> <chr>            <chr>              <chr>               <dbl>
#> 1          1 Sunil Huffmann   Strawberry yoghurt Lunch only              4
#> 2          2 Barclay Lynn     French fries       Lunch only              5
#> 3          3 Jayendra Lyne    <NA>               Breakfast and lunch     7
#> 4          4 Leon Rossini     Anchovies          Lunch only             NA
#> 5          5 Chidiegwu Dunkel Pizza              Breakfast and lunch     5
#> 6          6 Güvenç Attila    Ice cream          Lunch only              6

Esto hace que los CSV sean un poco poco confiables para almacenar en caché los resultados intermedios: debe volver a crear la especificación de la columna cada vez que carga. Hay dos alternativas principales:

  1. write_rds() y read_rds() son envoltorios uniformes alrededor de las funciones base readRDS() y saveRDS(). Estos almacenan datos en el formato binario personalizado de R llamado RDS:

    write_rds(students, "students.rds")
    read_rds("students.rds")
    #> # A tibble: 6 × 5
    #>   student_id full_name        favourite_food     meal_plan             age
    #>        <dbl> <chr>            <chr>              <fct>               <dbl>
    #> 1          1 Sunil Huffmann   Strawberry yoghurt Lunch only              4
    #> 2          2 Barclay Lynn     French fries       Lunch only              5
    #> 3          3 Jayendra Lyne    <NA>               Breakfast and lunch     7
    #> 4          4 Leon Rossini     Anchovies          Lunch only             NA
    #> 5          5 Chidiegwu Dunkel Pizza              Breakfast and lunch     5
    #> 6          6 Güvenç Attila    Ice cream          Lunch only              6
  2. El paquete arrow le permite leer y escribir archivos de parquet, un formato de archivo binario rápido que se puede compartir entre lenguajes de programación. Volveremos a arrow con más profundidad en Capítulo 22.

    library(arrow)
    write_parquet(students, "students.parquet")
    read_parquet("students.parquet")
    #> # A tibble: 6 × 5
    #>   student_id full_name        favourite_food     meal_plan             age
    #>        <dbl> <chr>            <chr>              <fct>               <dbl>
    #> 1          1 Sunil Huffmann   Strawberry yoghurt Lunch only              4
    #> 2          2 Barclay Lynn     French fries       Lunch only              5
    #> 3          3 Jayendra Lyne    NA                 Breakfast and lunch     7
    #> 4          4 Leon Rossini     Anchovies          Lunch only             NA
    #> 5          5 Chidiegwu Dunkel Pizza              Breakfast and lunch     5
    #> 6          6 Güvenç Attila    Ice cream          Lunch only              6

Parquet tiende a ser mucho más rápido que RDS y se puede usar fuera de R, pero requiere el paquete arrow.

7.6 Entrada de datos

A veces necesitará ensamblar un tibble “a mano” haciendo una pequeña entrada de datos en su script de R. Hay dos funciones útiles para ayudarlo a hacer esto, que difieren en si diseña el tibble por columnas o por filas. tibble() funciona por columna:

tibble(
  x = c(1, 2, 5), 
  y = c("h", "m", "g"),
  z = c(0.08, 0.83, 0.60)
)
#> # A tibble: 3 × 3
#>       x y         z
#>   <dbl> <chr> <dbl>
#> 1     1 h      0.08
#> 2     2 m      0.83
#> 3     5 g      0.6

Tenga en cuenta que todas las columnas en tibble deben tener el mismo tamaño, por lo que obtendrá un error si no lo son:

tibble(
  x = c(1, 2),
  y = c("h", "m", "g"),
  z = c(0.08, 0.83, 0.6)
)
#> Error in `tibble()`:
#> ! Tibble columns must have compatible sizes.
#> • Size 2: Existing data.
#> • Size 3: Column `y`.
#> ℹ Only values of size one are recycled.

Distribuir los datos por columna puede dificultar ver cómo se relacionan las filas, por lo que una alternativa es tribble(), abreviatura de tibble transpuesto (transposed tibble, en inglés), que le permite distribuir sus datos fila por fila. tribble() está personalizado para la entrada de datos en el código: los encabezados de las columnas comienzan con ~ y las entradas están separadas por comas. Esto hace posible diseñar pequeñas cantidades de datos en un formato fácil de leer:

tribble(
  ~x, ~y, ~z,
  "h", 1, 0.08,
  "m", 2, 0.83,
  "g", 5, 0.60,
)
#> # A tibble: 3 × 3
#>   x         y     z
#>   <chr> <dbl> <dbl>
#> 1 h         1  0.08
#> 2 m         2  0.83
#> 3 g         5  0.6

Usaremos tibble() y tribble() más adelante en el libro para construir pequeños ejemplos para demostrar cómo funcionan varias funciones.

7.7 Resumen

En este capítulo, ha aprendido a cargar archivos CSV con read_csv() y a realizar su propia entrada de datos con tibble() y tribble(). Ha aprendido cómo funcionan los archivos csv, algunos de los problemas que puede encontrar y cómo solucionarlos. Llegaremos a la importación de datos varias veces en este libro: Capítulo 20 desde Excel y Google Sheets, Capítulo 21 le mostrará cómo cargar datos desde bases de datos, Capítulo 22 desde archivos parquet, @ sec-rectangling de JSON y Capítulo 24 de sitios web.

Estamos casi al final de esta sección del libro, pero hay un último tema importante que cubrir: cómo obtener ayuda. Entonces, en el próximo capítulo, aprenderá algunos buenos lugares para buscar ayuda, cómo crear un reprex para maximizar sus posibilidades de obtener una buena ayuda y algunos consejos generales para mantenerse al día con el mundo de R.


  1. El paquete janitor no es parte de tidyverse, pero ofrece funciones útiles para la limpieza de datos y funciona bien dentro de las canalizaciones de datos que usa |>.↩︎