7  ✅ Importação de dados

7.1 Introdução

Trabalhar com dados fornecidos por pacotes em R é uma ótima maneira de aprender ferramentas de ciência de dados, mas você irá querer aplicar o que aprendeu aos seus próprios dados em algum momento. Neste capítulo, você aprenderá o básico sobre como ler arquivos de dados no R.

Especificamente, esse capítulo focará na leitura de arquivos de texto retangulares. Começaremos com conselhos práticos para lidar com recursos como nomes de colunas, tipos e dados ausentes. Você então aprenderá sobre como ler dados de múltiplos arquivos de uma única vez e exportar dados do R para um arquivo. Finalmente, você aprenderá a criar manualmente data frames no R.

7.1.1 Pré-requisitos

Neste capítulo, você irá aprender como importar arquivos de texto no R com o pacote readr, que faz parte do tidyverse.

7.2 Lendo dados de um arquivo

De início, vamos focar no tipo de arquivo de dados retangulares mais comum: CSV, que é a sigla em inglês para valores separados por vírgula (comma-separated values)1. Aqui está como um arquivo CSV simples se parece. A primeira linha, comumente chamada de linha de cabeçalho, fornece os nomes das colunas, e as seis linhas seguintes fornecem os dados. As colunas são separadas, ou delimitadas, por vírgulas.

ID Estudante,Nome Completo,comida.favorita,planoAlimentar,IDADE
1,Pedro Cardoso,Iogurte de morango,Só almoço,4     
2,Rafaela Lorenzoni,Batata frita,Só almoço,5       
3,Otávio Barros,N/A,Café da manhã e almoço,7       
4,Fernanda Melo,Brócolis,Só almoço,NA
5,Leopoldo Souza,Pizza,Café da manhã e almoço,cinco
6,Pérola Silva,Sorvete,Só almoço,6

Tabela 7.1 mostra uma representação dos mesmos dados como uma tabela.

Tabela 7.1: Dados do arquivo estudantes.csv como uma tabela.
ID Estudante Nome Completo comida.favorita planoAlimentar IDADE
1 Pedro Cardoso Iogurte de morango Só almoço 4
2 Rafaela Lorenzoni Batata frita Só almoço 5
3 Otávio Barros N/A Café da manhã e almoço 7
4 Fernanda Melo Brócolis Só almoço NA
5 Leopoldo Souza Pizza Café da manhã e almoço cinco
6 Pérola Silva Sorvete Só almoço 6

Podemos ler esse arquivo em R usando read_csv(). O primeiro argumento é o mais importante: o caminho para o arquivo. Você pode pensar no caminho como um endereço do arquivo: o nome do arquivo é estudantes.csv e ele está armazenado na pasta data.

estudantes <- read_csv("data/estudantes.csv")
#> Rows: 6 Columns: 5
#> ── Column specification ─────────────────────────────────────────────────────
#> Delimiter: ","
#> chr (4): Nome Completo, comida.favorita, planoAlimentar, IDADE
#> dbl (1): ID Estudante
#> 
#> ℹ 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.

O código acima irá funcionar se você tiver o arquivo estudantes.csv em uma pasta chamada data no seu projeto. Você pode baixar o arquivo estudantes.csv de https://raw.githubusercontent.com/cienciadedatos/pt-r4ds/traducao-pt-2ed/data/estudantes.csv ou você pode importá-lo diretamente dessa URL com:

estudantes <- read_csv("https://raw.githubusercontent.com/cienciadedatos/pt-r4ds/traducao-pt-2ed/data/estudantes.csv")

Quando você executa o comando read_csv(), ele imprime uma mensagem informando o número de linhas e colunas de dados, o delimitador que foi usado e as especificações das colunas (nomes das colunas organizados pelo tipo de dados que a coluna contém). Ele também imprime algumas informações sobre como recuperar a especificação completa da coluna e como silenciar essa mensagem. Essa mensagem é uma parte integral do readr, e voltaremos a ela em Seção 7.3.

7.2.1 Dicas práticas

Após importar os dados, o próximo passo geralmente envolve transformá-los de um jeito que facilite o trabalho no restante da sua análise. Com isso em mente, vamos dar uma segunda olhada no conjunto de dados estudantes.

estudantes
#> # A tibble: 6 × 5
#>   `ID Estudante` `Nome Completo`   comida.favorita    planoAlimentar    IDADE
#>            <dbl> <chr>             <chr>              <chr>             <chr>
#> 1              1 Pedro Cardoso     Iogurte de morango Só almoço         4    
#> 2              2 Rafaela Lorenzoni Batata frita       Só almoço         5    
#> 3              3 Otávio Barros     N/A                Café da manhã e … 7    
#> 4              4 Fernanda Melo     Brócolis           Só almoço         <NA> 
#> 5              5 Leopoldo Souza    Pizza              Café da manhã e … cinco
#> 6              6 Pérola Silva      Sorvete            Só almoço         6

Na coluna comida.favorita, há uma série de itens de comida, e o texto (string) "N/A", que deveria ter sido um NA real que o R reconheceria como um dado faltante (not available). Isso é algo que podemos resolver usando o argumento na. Por padrão, read_csv() reconhece apenas strings vazias ("") como NAs, mas, para esse conjunto de dados, também queremos que ele reconheça a string de caracteres "N/A".

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

estudantes
#> # A tibble: 6 × 5
#>   `ID Estudante` `Nome Completo`   comida.favorita    planoAlimentar    IDADE
#>            <dbl> <chr>             <chr>              <chr>             <chr>
#> 1              1 Pedro Cardoso     Iogurte de morango Só almoço         4    
#> 2              2 Rafaela Lorenzoni Batata frita       Só almoço         5    
#> 3              3 Otávio Barros     <NA>               Café da manhã e … 7    
#> 4              4 Fernanda Melo     Brócolis           Só almoço         NA   
#> 5              5 Leopoldo Souza    Pizza              Café da manhã e … cinco
#> 6              6 Pérola Silva      Sorvete            Só almoço         6

Você também pode notar que as colunas ID Estudante e Nome Completo estão cercadas por crases. Isso ocorre porque elas contêm espaços, quebrando as regras usuais do R para nomes de variáveis; elas são nomes não-sintáticos. Para se referir a essas variáveis, você precisa cercá-las com crases, `:

estudantes |> 
  rename(
    id_estudante = `ID Estudante`,
    nome_completo = `Nome Completo`
  )
#> # A tibble: 6 × 5
#>   id_estudante nome_completo     comida.favorita    planoAlimentar      IDADE
#>          <dbl> <chr>             <chr>              <chr>               <chr>
#> 1            1 Pedro Cardoso     Iogurte de morango Só almoço           4    
#> 2            2 Rafaela Lorenzoni Batata frita       Só almoço           5    
#> 3            3 Otávio Barros     <NA>               Café da manhã e al… 7    
#> 4            4 Fernanda Melo     Brócolis           Só almoço           NA   
#> 5            5 Leopoldo Souza    Pizza              Café da manhã e al… cinco
#> 6            6 Pérola Silva      Sorvete            Só almoço           6

Uma abordagem alternativa é usar janitor::clean_names() para transformar todos os nomes de variáveis em snake case de uma só vez2.

estudantes |> janitor::clean_names()
#> # A tibble: 6 × 5
#>   id_estudante nome_completo     comida_favorita    plano_alimentar     idade
#>          <dbl> <chr>             <chr>              <chr>               <chr>
#> 1            1 Pedro Cardoso     Iogurte de morango Só almoço           4    
#> 2            2 Rafaela Lorenzoni Batata frita       Só almoço           5    
#> 3            3 Otávio Barros     <NA>               Café da manhã e al… 7    
#> 4            4 Fernanda Melo     Brócolis           Só almoço           NA   
#> 5            5 Leopoldo Souza    Pizza              Café da manhã e al… cinco
#> 6            6 Pérola Silva      Sorvete            Só almoço           6

Outra tarefa comum após a leitura dos dados é examinar os tipos de variáveis. Por exemplo, plano_alimentar é uma variável categórica com um conjunto conhecido de valores possíveis, que no R deve ser representado como um fator:

estudantes |>
  janitor::clean_names() |>
  mutate(plano_alimentar = factor(plano_alimentar))
#> # A tibble: 6 × 5
#>   id_estudante nome_completo     comida_favorita    plano_alimentar     idade
#>          <dbl> <chr>             <chr>              <fct>               <chr>
#> 1            1 Pedro Cardoso     Iogurte de morango Só almoço           4    
#> 2            2 Rafaela Lorenzoni Batata frita       Só almoço           5    
#> 3            3 Otávio Barros     <NA>               Café da manhã e al… 7    
#> 4            4 Fernanda Melo     Brócolis           Só almoço           NA   
#> 5            5 Leopoldo Souza    Pizza              Café da manhã e al… cinco
#> 6            6 Pérola Silva      Sorvete            Só almoço           6

Note que os valores em plano_alimentar permaneceram os mesmos, mas o tipo de variável denotado abaixo do nome da variável mudou de caractere (<chr>) para fator (<fct>). Você aprenderá mais sobre fatores em Capítulo 16.

Antes de analisar esses dados, você provavelmente vai querer corrigir as colunas idade e id. Atualmente, idade é uma variável de caractere porque uma das observações está digitada como cinco em vez de um 5 numérico. Discutiremos os detalhes de como corrigir esse problema em Capítulo 20.

estudantes <- estudantes |>
  janitor::clean_names() |>
  mutate(
    plano_alimentar = factor(plano_alimentar),
    idade = parse_number(if_else(idade == "cinco", "5", idade))
  )

estudantes
#> # A tibble: 6 × 5
#>   id_estudante nome_completo     comida_favorita    plano_alimentar     idade
#>          <dbl> <chr>             <chr>              <fct>               <dbl>
#> 1            1 Pedro Cardoso     Iogurte de morango Só almoço               4
#> 2            2 Rafaela Lorenzoni Batata frita       Só almoço               5
#> 3            3 Otávio Barros     <NA>               Café da manhã e al…     7
#> 4            4 Fernanda Melo     Brócolis           Só almoço              NA
#> 5            5 Leopoldo Souza    Pizza              Café da manhã e al…     5
#> 6            6 Pérola Silva      Sorvete            Só almoço               6

Uma nova função aqui é if_else(), que tem três argumentos. O primeiro argumento test deve ser um vetor lógico. O resultado conterá o valor do segundo argumento, yes, quando test é TRUE, e o valor do terceiro argumento, no, quando é FALSE. Aqui estamos dizendo que se idade é a string de caracteres "cinco", faça-a "5", e se não, mantenha-a como idade. Você aprenderá mais sobre if_else() e vetores lógicos em Capítulo 12.

7.2.2 Outros argumentos

Há alguns outros argumentos importantes que precisamos mencionar, e eles serão mais fáceis de demonstrar se primeiro mostrarmos um truque útil: read_csv() pode ler strings de texto que você criou e formatou como um arquivo CSV:

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

Normalmente, read_csv() usa a primeira linha de dados como os nomes das colunas, o que é uma convenção muito comum. Mas não é incomum que algumas linhas de metadados sejam incluídas no início do arquivo. Você pode usar skip = n para pular as primeiras n linhas ou usar comment = "#" para ignorar todas as linhas que começam com #, por exemplo:

read_csv(
  "A primeira linha de metadados
  A segunda linha de metadados
  x,y,z
  1,2,3",
  skip = 2
)
#> # A tibble: 1 × 3
#>       x     y     z
#>   <dbl> <dbl> <dbl>
#> 1     1     2     3

read_csv(
  "# Um comentário que gostaria de ignorar
  x,y,z
  1,2,3",
  comment = "#"
)
#> # A tibble: 1 × 3
#>       x     y     z
#>   <dbl> <dbl> <dbl>
#> 1     1     2     3

Em outros casos, os dados podem não ter nomes de colunas. Você pode usar col_names = FALSE para dizer ao read_csv() para não tratar a primeira linha como cabeçalho e, em vez disso, rotular as colunas sequencialmente de 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, você pode fornecer à col_names um vetor de caracteres que será usado como os nomes das colunas:

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

Esses argumentos são tudo o que você precisa saber para ler a maioria dos arquivos CSV que você encontrará na prática. (Para o restante, você precisará inspecionar cuidadosamente seu arquivo .csv e ler a documentação para os muitos outros argumentos de read_csv().)

7.2.3 Outros tipos de arquivos

Uma vez que você tenha aprendido a usar read_csv(), usar as outras funções do readr é simples; é apenas uma questão de saber qual função usar:

  • read_csv2() lê arquivos separados por ponto-e-vírgula. Usa ; ao invés de , para separar os campos, e são comuns em países que usam , como marcador decimal.

  • read_tsv() lê arquivos delimitados por tabulação.

  • read_delim() lê arquivos com qualquer delimitador, tentando supor automaticamente o delimitador se você não o especificar.

  • read_fwf() lê arquivos de largura fixa. Você pode especificar os campos por suas larguras com fwf_widths() ou por suas posições com fwf_positions().

  • read_table() lê uma variação comum de arquivos de largura fixa onde as colunas são separadas por espaços em branco.

  • read_log() lê arquivos de log no estilo Apache.

7.2.4 Exercícios

  1. Que função você usaria para ler um arquivo onde os campos são separados por |?

  2. Além de file, skip e comment, quais outros argumentos read_csv() e read_tsv() têm em comum?

  3. Quais são os argumentos mais importantes para read_fwf()?

  4. Às vezes, as strings em um arquivo CSV contêm vírgulas. Para evitar que elas causem problemas, elas precisam ser cercadas por um caractere de citação, como " ou '. Por padrão, read_csv() assume que o caractere de citação será ". Para ler o seguinte texto em um data frame, que argumento para read_csv() você precisa especificar?

    "x,y\n1,'a,b'"
  5. Identifique o que está errado com cada um dos seguintes arquivos CSV em linha. O que acontece quando você executa o 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. Pratique se referir a nomes não-sintáticos no seguinte data frame:

    1. Extraindo a variável chamada 1.
    2. Plotando um gráfico de dispersão de 1 vs. 2.
    3. Criando uma nova coluna chamada 3, que é 2 dividido por 1.
    4. Renomeando as colunas para um, dois e três.
    irritante <- tibble(
      `1` = 1:10,
      `2` = `1` * 2 + rnorm(length(`1`))
    )

7.3 Controlando tipos de colunas

Um arquivo CSV não contém informações sobre o tipo de cada variável (ou seja, se é lógico, número, string, etc.), então readr tentará adivinhar o tipo. Esta seção descreve como o processo de adivinhação funciona, como resolver alguns problemas comuns que fazem com que ele falhe e, se necessário, como fornecer os tipos de coluna você mesmo. Por fim, mencionaremos algumas estratégias gerais que são úteis se o readr estiver falhando catastróficamente e você precisar obter mais informações sobre a estrutura do seu arquivo.

7.3.1 Adivinhando tipos

O pacote readr usa uma heurística para descobrir os tipos de coluna. Para cada coluna, ele pega os valores de 1.0003 linhas espaçadas uniformemente da primeira à última, ignorando os valores ausentes. Ele então trabalha através das seguintes perguntas:

  • Contém apenas F, T, FALSE ou TRUE (ignorando a caixa alta)? Se sim, é um lógico.
  • Contém apenas números (por exemplo, 1, -4.5, 5e6, Inf)? Se sim, é um número.
  • Corresponde ao padrão ISO8601? Se sim, é uma data ou data-hora. (Voltaremos às data-horas em mais detalhes em Seção 17.2).
  • Caso contrário, deve ser uma string.

Você pode ver esse comportamento em ação neste exemplo simples:

read_csv("
  logico,numerico,data,string
  TRUE,1,2021-01-15,abc
  false,4.5,2021-02-15,def
  T,Inf,2021-02-16,ghi
")
#> # A tibble: 3 × 4
#>   logico numerico data       string
#>   <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

Essa heurística funciona bem se você tiver um conjunto de dados limpo, mas, na vida real, você encontrará uma seleção de falhas estranhas e belas.

7.3.2 Valores ausentes, tipos de coluna e problemas

A forma mais comum de falha na detecção de coluna é quando uma coluna contém valores inesperados, e você obtém uma coluna de caracteres em vez de um tipo mais específico. Uma das causas mais comuns para isso é um valor ausente registrado usando algo diferente do NA que o readr espera.

Considere este exemplo simples de um arquivo CSV com 1 coluna:

simple_csv <- "
  x
  10
  .
  20
  30"

Se o lermos sem argumentos adicionais, x se torna uma coluna de caracteres:

read_csv(simple_csv)
#> # A tibble: 4 × 1
#>   x    
#>   <chr>
#> 1 10   
#> 2 .    
#> 3 20   
#> 4 30

Nesse pequeno exemplo, você pode ver facilmente o valor ausente .. Mas o que acontece se você tiver milhares de linhas com apenas alguns valores ausentes representados por .s espalhados entre eles? Uma abordagem é dizer ao readr que x é uma coluna numérica e, em seguida, ver onde ele falha. Você pode fazer isso com o argumento col_types, que aceita uma lista nomeada onde os nomes correspondem aos nomes das colunas no arquivo CSV:

df <- read_csv(
  simple_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)

Agora read_csv() relata que houve um problema e nos diz que podemos descobrir mais com problems():

problems(df)
#> # A tibble: 1 × 5
#>     row   col expected actual file                                           
#>   <int> <int> <chr>    <chr>  <chr>                                          
#> 1     3     1 a double .      /private/var/folders/st/0346cszj61928zc133bfr8…

Isso nos diz que houve um problema na linha 3, coluna 1, onde o readr esperava um número real, mas obteve um .. Isso sugere que este conjunto de dados usa . para valores ausentes. Então, definimos na = ".", a adivinhação automática tem sucesso, nos dando a coluna numérica que queremos:

read_csv(simple_csv, na = ".")
#> # A tibble: 4 × 1
#>       x
#>   <dbl>
#> 1    10
#> 2    NA
#> 3    20
#> 4    30

7.3.3 Tipos de colunas

O pacote readr fornece um total de nove tipos de coluna para você usar:

  • col_logical() e col_double() leem lógicos e números reais. É relativamente raro serem necessários (exceto como acima), já que o readr geralmente os adivinhará para você.
  • col_integer() lê números inteiros (integer). Raramente distinguimos os números inteiros (integer) e reais (doubles) neste livro porque eles são funcionalmente equivalentes, mas ler números inteiros explicitamente pode ocasionalmente ser útil porque ocupam metade da memória dos números reais.
  • col_character()strings. Isso pode ser útil para especificar explicitamente quando você tem uma coluna que é um identificador numérico, ou seja, longas séries de dígitos que identificam um objeto, mas onde não faz sentido aplicar operações matemáticas. Exemplos incluem números de telefone, números de seguro social, números de cartão de crédito, etc.
  • col_factor(), col_date() e col_datetime() criam fatores, datas e data-horas, respectivamente; você aprenderá mais sobre esses tipos de dados quando chegarmos a eles em Capítulo 16 e Capítulo 17.
  • col_number() é um analisador numérico permissivo que ignorará componentes não numéricos, e é particularmente útil para moedas. Você aprenderá mais sobre ele em Capítulo 13.
  • col_skip() pula uma coluna para que ela não seja incluída no resultado, o que pode ser útil para acelerar a leitura dos dados se você tiver um arquivo CSV grande e quiser usar apenas algumas das colunas.

Também é possível substituir a coluna padrão trocando de list() para cols() e especificando .default:

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

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

Outra função auxiliar útil é cols_only(), que lerá apenas as colunas que você especificar:

read_csv(
  outro_csv,
  col_types = cols_only(x = col_character())
)
#> # A tibble: 1 × 1
#>   x    
#>   <chr>
#> 1 1

7.4 Importando dados de múltiplos arquivos

Às vezes seus dados estão divididos em vários arquivos em vez de estarem contidos em um único arquivo. Por exemplo, você pode ter dados de vendas para vários meses, com os dados de cada mês em um arquivo separado: 01-vendas.csv para janeiro, 02-vendas.csv para fevereiro e 03-vendas.csv para março.

arquivos_vendas <- c("data/01-vendas.csv", "data/02-vendas.csv", "data/03-vendas.csv")
read_csv(arquivos_vendas, id = "arquivo")
#> # A tibble: 19 × 6
#>   arquivo            mes       ano marca  item     n
#>   <chr>              <chr>   <dbl> <dbl> <dbl> <dbl>
#> 1 data/01-vendas.csv Janeiro  2019     1  1234     3
#> 2 data/01-vendas.csv Janeiro  2019     1  8721     9
#> 3 data/01-vendas.csv Janeiro  2019     1  1822     2
#> 4 data/01-vendas.csv Janeiro  2019     2  3333     1
#> 5 data/01-vendas.csv Janeiro  2019     2  2156     9
#> 6 data/01-vendas.csv Janeiro  2019     2  3987     6
#> # ℹ 13 more rows

Mais uma vez, o código acima funcionará apenas se você tiver os arquivos CSV em uma pasta chamada data no seu projeto. Você pode baixar esses arquivos de https://raw.githubusercontent.com/cienciadedatos/pt-r4ds/traducao-pt-2ed/data/01-vendas.csv, https://raw.githubusercontent.com/cienciadedatos/pt-r4ds/traducao-pt-2ed/data/02-vendas.csv e https://raw.githubusercontent.com/cienciadedatos/pt-r4ds/traducao-pt-2ed/data/03-vendas.csv ou você pode lê-los diretamente com:

arquivos_vendas <- c(
  "https://raw.githubusercontent.com/cienciadedatos/pt-r4ds/traducao-pt-2ed/data/01-vendas.csv",
  "https://raw.githubusercontent.com/cienciadedatos/pt-r4ds/traducao-pt-2ed/data/02-vendas.csv",
  "https://raw.githubusercontent.com/cienciadedatos/pt-r4ds/traducao-pt-2ed/data/03-vendas.csv"
)
read_csv(arquivos_vendas, id = "arquivo")

O argumento id adiciona uma nova coluna chamada arquivo ao data frame resultante que identifica o arquivo de onde os dados vêm. Isso é especialmente útil nas circunstâncias em que os arquivos que você está lendo não têm uma coluna de identificação que possa ajudá-lo a rastrear as observações até suas fontes originais.

Se você tiver muitos arquivos que deseja ler, pode ser complicado escrever seus nomes como uma lista. Em vez disso, você pode usar a função list.files() para encontrar os arquivos para você, identificando um padrão nos nomes dos arquivos. Você aprenderá mais sobre esses padrões em Capítulo 15.

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

7.5 Exportando para um arquivo

O pacote readr também vem com duas funções úteis para escrever dados de volta para o disco: write_csv() e write_tsv(). Os argumentos mais importantes para essas funções são x (o data frame a ser salvo) e file (o local para salvá-lo). Você também pode especificar como os valores ausentes são escritos com na, e se você deseja acrescentar as linhas em um arquivo existente, utilizando o argumento append.

write_csv(estudantes, "estudantes.csv")

Agora, vamos ler esse arquivo CSV novamente. Observe que as informações de tipo de variável que você acabou de configurar são perdidas quando você salva em CSV porque você está começando de novo com a leitura de um arquivo de texto simples:

estudantes
#> # A tibble: 6 × 5
#>   id_estudante nome_completo     comida_favorita    plano_alimentar     idade
#>          <dbl> <chr>             <chr>              <fct>               <dbl>
#> 1            1 Pedro Cardoso     Iogurte de morango Só almoço               4
#> 2            2 Rafaela Lorenzoni Batata frita       Só almoço               5
#> 3            3 Otávio Barros     <NA>               Café da manhã e al…     7
#> 4            4 Fernanda Melo     Brócolis           Só almoço              NA
#> 5            5 Leopoldo Souza    Pizza              Café da manhã e al…     5
#> 6            6 Pérola Silva      Sorvete            Só almoço               6
write_csv(estudantes, "estudantes-2.csv")
read_csv("estudantes-2.csv")
#> # A tibble: 6 × 5
#>   id_estudante nome_completo     comida_favorita    plano_alimentar     idade
#>          <dbl> <chr>             <chr>              <chr>               <dbl>
#> 1            1 Pedro Cardoso     Iogurte de morango Só almoço               4
#> 2            2 Rafaela Lorenzoni Batata frita       Só almoço               5
#> 3            3 Otávio Barros     <NA>               Café da manhã e al…     7
#> 4            4 Fernanda Melo     Brócolis           Só almoço              NA
#> 5            5 Leopoldo Souza    Pizza              Café da manhã e al…     5
#> 6            6 Pérola Silva      Sorvete            Só almoço               6

Isso faz arquivos CSVs um pouco não confiáveis para armazenar resultados intermediários — você precisa recriar a especificação das colunas toda vez que carrega os dados. Existem duas formas principais:

  1. write_rds() e read_rds() são wrappers uniformes4 em torno das funções base readRDS() e saveRDS(). Eles armazenam dados no formato binário personalizado do R chamado RDS. Isso significa que quando você recarrega o objeto, você está carregando exatamente o mesmo objeto R que você armazenou.

    write_rds(estudantes, "estudantes.rds")
    read_rds("estudantes.rds")
    #> # A tibble: 6 × 5
    #>   id_estudante nome_completo     comida_favorita    plano_alimentar     idade
    #>          <dbl> <chr>             <chr>              <fct>               <dbl>
    #> 1            1 Pedro Cardoso     Iogurte de morango Só almoço               4
    #> 2            2 Rafaela Lorenzoni Batata frita       Só almoço               5
    #> 3            3 Otávio Barros     <NA>               Café da manhã e al…     7
    #> 4            4 Fernanda Melo     Brócolis           Só almoço              NA
    #> 5            5 Leopoldo Souza    Pizza              Café da manhã e al…     5
    #> 6            6 Pérola Silva      Sorvete            Só almoço               6
  2. O pacote arrow te permite importar e exportar arquivos parquet, um formato de arquivo binário rápido que pode ser compartilhado entre diferentes linguagens de programação. Voltaremos ao arrow com mais detalhes em Capítulo 22.

    library(arrow)
    write_parquet(estudantes, "estudantes.parquet")
    read_parquet("estudantes.parquet")
    # A tibble: 6 × 5
    #   id_estudante nome_completo     comida_favorita
    #          <dbl> <chr>             <chr>          
    # 1            1 Pedro Cardoso     Iogurte de mor…
    # 2            2 Rafaela Lorenzoni Batata frita   
    # 3            3 Otávio Barros     <NA>           
    # 4            4 Fernanda Melo     Brócolis       
    # 5            5 Leopoldo Souza    Pizza          
    # 6            6 Pérola Silva      Sorvete        
    # # ℹ 2 more variables: plano_alimentar <fct>,
    # #   idade <dbl>

Parquet tende a ser muito mais rápido que RDS e é utilizável fora do R, mas requer o pacote arrow.

7.6 Entrada de dados

Às vezes você precisará montar um tibble “à mão” fazendo um pouco de entrada de dados no seu script R. Existem duas funções úteis para ajudá-lo a fazer isso que diferem se você organiza o tibble por colunas ou por linhas. tibble() funciona por coluna:

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

Laying out the data by column can make it hard to see how the rows are related, so an alternative is tribble(), short for transposed tibble, which lets you lay out your data row by row. tribble() é customizado para entrada de dados no código: os cabeçalhos das colunas começam com ~ e as entradas são separadas por vírgulas. Isso torna possível dispor pequenas quantidades de dados em uma forma fácil de ler:

Inserir os dados por coluna pode dificultar a visualização de como as linhas estão relacionadas, então uma alternativa é tribble(), abreviação de transposed tibble (tibble transposta), que permite organizar seus dados linha por linha.

tribble(
  ~x, ~y, ~z,
  1, "h", 0.08,
  2, "m", 0.83,
  5, "g", 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

7.7 Resumo

Neste capítulo, você aprendeu como carregar arquivos CSV com read_csv() e como inserir seus próprios dados com tibble() e tribble(). Você aprendeu como arquivos CSV funcionam, alguns dos problemas que você pode encontrar e como superá-los. Voltaremos à importação de dados algumas vezes neste livro: Capítulo 20 do Excel e do Google Planilhas, Capítulo 21 mostrará para você como carregar dados de bancos de dados, Capítulo 22 de arquivos parquet, Capítulo 23 de JSON e Capítulo 24 de sites.

Estamos quase no final desta seção do livro, mas há um último tópico importante a ser coberto: como obter ajuda. Então, no próximo capítulo, você aprenderá alguns bons lugares para procurar ajuda, como criar um exemplo reprodutível (reprex)5 para maximizar suas chances de obter boa ajuda e alguns conselhos gerais sobre como acompanhar o mundo do R.


  1. No Brasil, é mais comum o tipo CSV2, que utiliza ponto-e-vírgula como separador e é, portanto, compatível com o uso da vírgula como separador decimal. (N. dos T.)↩︎

  2. O pacote janitor não faz parte do tidyverse, mas oferece funções úteis para limpeza de dados e funciona bem em pipelines de dados que usam |>.↩︎

  3. Você pode substituir o padrão de 1.000 com o argumento guess_max.↩︎

  4. No contexto de wrappers, funções ou métodos construídos como uma camada de abstração mais simples e consistente sobre outras funções ou métodos existentes, uniforme significa que o wrapper oferece uma interface padronizada em relação à outras funções e métodos de operações similares, oferecendo uma interação mais previsível ao usuário. (N. dos T.)↩︎

  5. Reprex é o acrônimo para Reproducible Example (exemplo reprodutível). (N. dos T.)↩︎