Capítulo 4 Importação e Exportação de Dados Locais

Conforme vimos no capítulo 3, a primeira etapa de uma pesquisa é a importação de dados. Nesta seção iremos aprender a importar e exportar dados contidos em arquivos locais. No próximo capítulo aprenderemos a importar dados de forma mais dinâmica, utilizando pacotes especializados e uma conexão a Internet.

Existem diferentes formatos de armazenamento de dados em arquivos. É impossível tratar todos os casos, porém iremos traçar uma lista abrangente com os seguintes formatos e extensões de arquivos:

  • Dados delimitados em texto (csv);
  • Microsoft Excel (xls, xlsx);
  • Arquivos nativos do R (RData e rds)
  • Formato fst (fst)
  • SQLite (SQLITE)
  • Texto não estruturado (txt).

Cada um desses possui sua própria particularidade. Os benefícios entre um formato e outro mudam de acordo com a situação. Na última seção do capítulo iremos discorrer sobre o processo de seleção de formato. Em geral, o formato mais flexível e utilizado é .csv.

A primeira lição na importação de dados para o R é que o local do arquivo deve ser indicado explicitamente no código. Este endereço é passado para a função que irá ler o arquivo. Veja a definição a seguir:

my.file <- 'C:/Data/MyData.csv'

Note o uso de barras (/) para designar o diretório do arquivo. Referências relativas também funcionam, tal como em:

my.file <- 'Data/MyData.csv'

Neste caso, assume-se que na pasta atual de trabalho existe um diretório chamado Data e, dentro desse, um arquivo denominado MyData.csv. Se o endereço do arquivo é simplesmente o seu nome, assume-se que o mesmo encontra-se na raiz da pasta de trabalho. Para verificar o endereço atual de trabalho, utilize a função getwd.

Um ponto bastante importante aqui é que os dados serão importados e exportados no R como objetos do tipo dataframe. Isto é, uma tabela contida em um arquivo Excel ou .csv se transformará em um objeto no ambiente de trabalho do R após a importação. Quando exportarmos dados, o formato mais comum é esse mesmo objeto, um dataframe. Convenientemente, dataframes são nada mais que tabelas, com linhas e colunas. Cada coluna do dataframe terá a sua própria classe, sendo as mais comuns:

  • Numérica (numeric)
  • Texto (character)
  • Fator (factor)
  • Data (Date)

É de fundamental importância que os dados sejam representados na classe correta. Uma vasta quantidade de erros podem ser evitados pela simples checagem das classes das colunas no dataframe resultante do processo de importação. Por enquanto somente é necessário entender esta propriedade básica de dataframes. Estudaremos esse objeto mais profundamente no capítulo 6 e as classes básicas de objetos no capítulo 7. Vamos partir para o estudo das funções e pacotes para a importação e exportação de cada formato de arquivo.

4.1 Arquivos csv

Considere o arquivo de dados no formato csv chamado 'Ibov.csv', localizado na pasta data no diretório atual de trabalho. Esse arquivo contém dados diários do índice Ibovespa de 2010-01-04 até 2020-07-29. Observe que se trata de um simples arquivo de texto estruturado em linhas e colunas. O mesmo pode ser aberto e modificado em qualquer editor de texto. A primeira linha apresenta os nomes das colunas – linha também chamada de cabeçalho (header) – e todas as colunas são separadas por vírgulas (,). Esse é um padrão internacional para esse tipo de arquivo.

No caso brasileiro, esse padrão internacional gera confusão, pois a vírgula também pode indicar valores decimais em dados numéricos. Para evitar problemas na importação dos dados, caso você encontre um arquivo onde os valores decimais são definidos por vírgula, abra-o em um editor de texto qualquer e substitua todos os valores de vírgula por ponto (.). Isso deixa o arquivo em um formato internacional. No Windows, programas como o Notepad e o Notepad++ realizam essa tarefa facilmente.

Destaca-se que, no formato brasileiro, é comum utilizar a semi-vírgula (;) para separar colunas, enquanto no formato internacional o mais comum é a vírgula (,). Caso não seja possível converter os dados para o formato internacional, pode-se utilizar funções específicas que assumem que o indicador de decimal é a vírgula e o separação de colunas é o ponto-e-vírgula (;).

Como sugestão para evitar problemas, antes de prosseguir para a importação de dados em um arquivo .csv, deve-se abrir o arquivo em um editor de texto qualquer e verificar:

  1. A existência de texto antes dos dados e a necessidade de ignorar algumas linhas iniciais;
  2. A existência ou não dos nomes das colunas;
  3. O símbolo separador de colunas;
  4. O símbolo de decimal, o qual deve ser o ponto (.).

Na maioria dos casos, os dados podem ser importados diretamente. Porém, os itens anteriores devem ser checados para evitar problemas na importação.

4.1.1 Importação de Dados

O R possui funções nativas para importar dados de arquivos .csv, read.csv e read.csv2. Porém, esse é um dos casos em que o tidyverse oferece melhores opções, com maior velocidade de leitura e melhor tratamento das classes de colunas. Portanto, utilizamos a função read_csv do pacote readr para ler os dados do arquivo data/Ibov.csv. Veja um exemplo de uso:

library(readr)

# set file
my.f <- 'data/Ibov.csv'

# read data
my.df.ibov <- read_csv(my.f)
## Parsed with column specification:
## cols(
##   ref.date = col_date(format = ""),
##   price.close = col_double()
## )

Observe como o código anterior apresentou a mensagem “Parsed with column specification: …”. Essa mensagem mostra como a função identifica as classes das colunas lendo as primeiras 1000 linhas do arquivo. Regras inteligentes tentam prever a classe com base no conteúdo importado. Podemos usar essas informações em nosso próprio código copiando o texto e atribuindo-o a uma variável:

# set cols from readr import message
my.cols <- cols(
  price.close = col_integer(),
  ref.date = col_date(format = "")
)

# read file with readr::read_csv
my.df.ibov <- read_csv(my.f,
                       col_types = my.cols)

Agora, vamos checar a classe das nossas colunas. Para isso, utilizamos a função glimpse do pacote dplyr:

# print column classes
dplyr::glimpse(my.df.ibov)
## Rows: 2,630
## Columns: 2
## $ ref.date    <date> 2010-01-04, 2010-01-05, 2010-01-06, …
## $ price.close <int> 70045, 70240, 70729, 70451, 70263, 70…

Verificando a importação, temos duas colunas. A primeira é ref.date, com classe date. A segunda é price.close, da classe int (integer) - número inteiro.

No uso de readr::read_csv, um possível conjunto de etapas é:

  1. ler o arquivo sem argumentos em read_csv,
  2. copiar o texto das classes de coluna padrão da mensagem de saída
  3. adicionar o texto anterior como argumento col_types

O conjunto de passos anterior é suficiente para a grande maioria dos casos. O uso da mensagem com as classes das colunas é particularmente útil quando o arquivo importado tem várias colunas e a definição manual de cada classe exige muita digitação.

Indo além, função read_csv possui diversas outras opções tais como:

  • modificação do formato dos dados de importação (opção locale)
  • pular n linhas antes da importação (opção skip)
  • definição customizada para valores NA (opção na)

entre várias outras possibilidades. O pacote readr também possui várias outras funções para situações específicas de importação. Caso a função read_csv não resolva o seu problema na leitura de algum arquivo texto estruturado, certamente outra função desse pacote resolverá.

4.1.2 Exportação de Dados

Para escrever um arquivo .csv, basta utilizar a função readr::write_csv. No próximo exemplo iremos criar dados artificiais, salvar em um dataframe e exportar para um arquivo .csv. Veja a seguir:

library(readr)

# set number of observations
N <- 100

# create dataframe with random data
my.df <- data.frame(y = runif(N),
                    z = rep('a',N))

# write to file
f.out <- 'data/temp.csv'
write_csv(x = my.df, path = f.out)

No exemplo anterior, salvamos o dataframe chamado my.df para o arquivo temp.csv, localizado na pasta data do diretório de trabalho. Podemos verificar o arquivo importando o seu conteúdo:

my.df.import <- read_csv(f.out,
                         col_types = cols(y = col_double(),
                                          z = col_character() ) )
print(head(my.df.import))
## # A tibble: 6 x 2
##       y z    
##   <dbl> <chr>
## 1 0.665 a    
## 2 0.968 a    
## 3 0.161 a    
## 4 0.669 a    
## 5 0.702 a    
## 6 0.519 a

O resultado está conforme o esperado, um dataframe com duas colunas, a primeira com números e a segunda com texto.

4.2 Arquivos Excel (xls e xlsx)

Em Finanças e Economia, é bastante comum encontrarmos dados salvos em arquivos do tipo Microsoft Excel, com extensão xls ou xlsx. Apesar de não ser um formato de armazenamento de dados eficiente, esse é um programa de planilha bastante popular devido às suas funcionalidades. É muito comum que informações sejam armazenadas e distribuídas dessa forma. Por exemplo: dados históricos do Tesouro Direto são disponibilizados como arquivos .xls no site do tesouro nacional. A CVM (Comissão de Valores Mobiliários) e ANBIMA (Associação Brasileira das Entidades dos Mercados Financeiro e de Capitais) também tem preferência por esse tipo de formato em alguns dados publicados em seu site.

4.2.1 Importação de Dados

O R não possui uma função nativa para importar dados do Excel e, portanto, deve-se instalar e utilizar certos pacotes para realizar essa operação. Existem diversas opções, porém, os principais pacotes são XLConnect (Mirai Solutions GmbH 2016), xlsx (Dragulescu 2014) e readxl (Wickham 2016a).

Apesar de os pacotes anteriores terem objetivos semelhantes, cada um tem suas peculiaridades. Caso a leitura de arquivos do Excel seja algo importante no seu trabalho, aconselho-o fortemente a estudar as diferenças entre esses pacotes. Nesta seção, daremos prioridade para funções do pacote readxl, que é um dos mais fáceis e diretos de utilizar, além de não necessitar de outros softwares instalados (tal como o Java). Para instalar o referido pacote, basta utilizar a função install.packages:

install.packages('readxl')

Imagine agora a existência de um arquivo chamado Ibov_xls.xlsx que contenha os mesmos dados do Ibovespa. A importação das informações contidas nesse arquivo para o R seria realizada através da função read_excel:

library(readxl)
library(dplyr)

# set file
my.f <- 'data/Ibov_xlsx.xlsx'

# read xlsx into dataframe
my.df <- read_excel(my.f, sheet = 'Sheet1')

# glimpse contents
glimpse(my.df)
## Rows: 2,630
## Columns: 2
## $ ref.date    <dttm> 2010-01-04, 2010-01-05, 2010-01-06, …
## $ price.close <dbl> 70045, 70240, 70729, 70451, 70263, 70…

Observe que, nesse caso, as datas já foram importadas com a formatação correta na classe dttm (datetime). Essa é uma vantagem ao utilizar arquivos do Excel: a classe dos dados do arquivo original é levada em conta no momento da importação. O lado negativo desse formato é a baixa portabilidade dos dados e o maior tempo necessário para a execução da importação. Como regra geral, dados importados do Excel apresentarão um tempo de carregamento mais alto do que dados importados de arquivos .csv.

4.2.2 Exportação de Dados

A exportação para arquivo Excel também é fácil. Assim como para a importação, não existe uma função nativa do R que execute esse procedimento. Podemos, porém, utilizar pacotes xlsx (Dragulescu 2014) e writexl (Ooms 2017) para esse objetivo. Uma diferença aqui é que o pacote xlsx oferece mais funcionalidade mas exige a instalação do Java JDK no sistema operacional. No caso do Windows, basta visitar o site do Java e instalar o software na versão 64 bits (opção Windows Off-line (64 bits)). Logo após, instale o pacote xlsx normalmente no R com o comando install.packages('xlsx').

Vamos começar com um exemplo para xlsx

library(xlsx)

# set number of rows
N <- 50

# create random dataframe
my.df <- data.frame(y = seq(1,N),
                    z = rep('a',N))

# write to xlsx
f.out <- 'data/temp.xlsx'
write.xlsx(x = my.df,
           file = f.out,
           sheetName = "my df")

Note que uma diferença nos argumentos da função write.xlsx é que é necessário incluir o nome da aba do arquivo Excel onde os dados da tabela serão exportados. Para exportar várias informações para um mesmo arquivo, é necessário utilizar o argumento append da função write.xlsx. Caso contrário, a função irá criar um novo arquivo em cada chamada da mesma. Veja o exemplo a seguir, onde exportamos dois dataframes para duas abas diferentes do mesmo arquivo Excel:

# set number of rows
N <- 25

# create random dfs
my.df.A <- data.frame(y = seq(1,N),
                      z = rep('a',N))

my.df.B <- data.frame(z = rep('b',N))

# write both df to single file
f.out <- 'data/temp.xlsx'
write.xlsx(x = my.df.A,
           file = f.out,
           sheetName = "my df A")

write.xlsx(x = my.df.B,
           file = f.out,
           sheetName = "my df B",
           append = TRUE )

Após a exportação, podes verificar o conteúdo dos arquivos abrindo-o no Excel.

O diferencial do pacote writexl em relação a xlsx é a não necessidade do Java, e a rapidez de execução. O lado negativo é que não permite a escolha das abas para a cópia. Veja a seguir:

library(writexl)
# set number of rows
N <- 25

# create random dfs
my.df.A <- data.frame(y = seq(1,N),
                      z = rep('a',N))

write_xlsx(x = my.df.A,
           path = f.out)

Para comparar o desempenho, vamos verificar a diferença de tempo de execução entre um e outro:

library(writexl)
library(readxl)
library(xlsx)

# set number of rows
N <- 2500

# create random dfs
my.df.A <- data.frame(y = seq(1,N),
                      z = rep('a',N))

# set files
my.file.1 <- 'data/temp_writexl.xlsx'
my.file.2 <- 'data/temp_xlsx.xlsx'

# test export
time.write.writexl <- system.time(write_xlsx(x = my.df.A,
                                             path = my.file.1 ))

time.write.xlsx <- system.time(write.xlsx(x = my.df.A,
                                          file = my.file.2 ))

# test read
time.read.readxl <- system.time(read_xlsx(path = my.file.1 ))
time.read.xlsx <- system.time(read.xlsx(file = my.file.2,
                                        sheetIndex = 1 ))

Após a execução, vamos verificar a diferença de tempo:

# results
my.formats <- c('xlsx', 'readxl')
results.read <- c(time.read.xlsx[3], time.read.readxl[3])
results.write<- c(time.write.xlsx[3], time.write.writexl[3])

# print text
my.text <- paste0('\nTime to WRITE dataframe with ',
                  my.formats, ': ',
                  results.write, ' seconds', collapse = '')
cat(my.text)

my.text <- paste0('\nTime to READ dataframe with ',
                  my.formats, ': ',
                  results.read, ' seconds', collapse = '')
cat(my.text)
## 
## Time to WRITE dataframe with xlsx: 1.686 seconds
## Time to WRITE dataframe with readxl: 0.0109999999999992 seconds
## Time to READ dataframe with xlsx: 2.958 seconds
## Time to READ dataframe with readxl: 0.00900000000000034 seconds

Como podemos ver, mesmo para dados de pouco volume, um dataframe com 2500 linhas e 2 colunas, a diferença de tempo de execução é significativa. Caso estiveres trabalhando com grandes planilhas, o uso de pacotes readxl e writexl é fortemente recomendado. Porém, como já mostrado anteriormente, as funções de xlsx oferecem algumas funcionalidades extras.

4.3 Arquivos RData/rds

O R possui dois formatos nativos para salvar objetos de sua área de trabalho para um arquivo local com extensão RData ou rds. O grande benefício, em ambos os casos, é que o arquivo resultante é compacto e o seu acesso é muito rápido. A desvantagem é que os dados perdem portabilidade para outros programas. A diferença entre um formato e outro é que arquivos RData podem salvar mais de um objeto, enquanto o formato .rds salva apenas um.

4.3.1 Importação de Dados

Para carregar os dados de um aquivo RData, utilizamos a função load:

# set file path (objects my.x and my.y)
my.file <- 'data/temp.RData'

# load all contents into workspace
load(file = my.file)

O arquivo data/temp.RData continha dois objetos, my.x e my.y, os quais foram carregados na memória do R.

O processo de importação para arquivos .rds é muito semelhante. A diferença é no uso da função readRDS:

# set file path
my.file <- 'data/temp.rds'

# load content into workspace
my.x <- readRDS(file = my.file)

Comparando o código entre o uso de arquivos .RData e .rds, note que um benefício no uso de .rds é a explícita definição do objeto na área de trabalho. Isto é, o conteúdo de my.file em readRDS é explicitamente salvo em my.x. Quando usamos a função load, no código não fica claro qual o nome do objeto que foi importado. Isso é particularmente inconveniente quando é necessário modificar o nome do objeto importado.

Como sugestão, dê preferência ao uso do formato .rds. Entendo que esse é mais prático, deixando o código mais claro. A diferença de velocidade de acesso e gravação entre um e outro é mínima. O benefício de importar vários objetos em um mesmo arquivo com o formato RData torna-se irrelevante quando no uso de objetos do tipo lista, os quais podem incorporar outros objetos no seu conteúdo. Veremos mais detalhes sobre este tipo de objeto no capítulo 6

4.3.2 Exportação de Dados

Para criar um novo arquivo RData, utilizamos a função save. Veja o exemplo a seguir, onde criamos um arquivo RData com dois objetos:

# set vars
my.x <- 1:100
my.y <- 1:100

# write to RData
my.file <- 'data/temp.RData'
save(list = c('my.x', 'my.y'),
     file = my.file)

Podemos verificar a existência do arquivo com a função file.exists:

file.exists(my.file)
## [1] TRUE

Observe que o arquivo data/temp.RData está disponível na pasta data.

Já para arquivos .rds, salvamos o objeto com função saveRDS:

# set data and file
my.x <- 1:100
my.file <- 'data/temp.rds'

# save as .rds
saveRDS(object = my.x,
        file = my.file)

# read it
my.x2 <- readRDS(file = my.file)

# test equality
print(identical(my.x, my.x2))
## [1] TRUE

O comando identical testa a igualdade entre os objetos e mostra que são exatamente iguais.

4.4 Arquivos fst (pacote fst)

Uma recente inovação no ambiente R diz respeito ao armazenamento de dados locais com o formato fst. Esse foi especialmente desenhado para possibilitar a gravação e leitura de dados tabulares de forma rápida e com mínimo uso do espaço no disco. O uso deste formato é particularmente benéfico quando se está trabalhando com volumosas bases de dados.

4.4.1 Importação de Dados

O uso é bastante simples. Utilizamos a função read_fst para ler arquivos fst.

library(fst)

my.file <- 'data/temp.fst'
my.df <- read_fst(my.file)

glimpse(my.df)
## Rows: 1,000
## Columns: 1
## $ x <dbl> 0.55068951, 0.46197171, 0.95264565, 0.35005803,…

Assim como para os demais casos, os dados estão disponíveis na área de trabalho após a importação.

4.4.2 Exportação de Dados

Utilizamos a função write_fst para gravar arquivos no formato fst, :

library(fst)

# create dataframe
N <- 1000
my.file <- 'data/temp.fst'
my.df <- data.frame(x = runif(N))

# write to fst
write_fst(x = my.df, path = my.file)

Como um teste do potencial do formato fst, a seguir vamos cronometrar o tempo de leitura e gravação entre fst e rds para um dataframe com grande quantidade de dados: 2,500,000 linhas e 2 colunas. Iremos reportar também o tamanho do arquivo resultante.

library(fst)

# set number of rows
N <- 2500000

# create random dfs
my.df <- data.frame(y = seq(1,N),
                    z = rep('a',N))

# set files
my.file.1 <- 'data/temp_rds.rds'
my.file.2 <- 'data/temp_fst.fst'

# test write
time.write.rds <- system.time(saveRDS(my.df, my.file.1 ))
time.write.fst <- system.time(write_fst(my.df, my.file.2 ))

# test read
time.read.rds <- system.time(readRDS(my.file.1))
time.read.fst <- system.time(read_fst(my.file.2))

# test file size (MB)
file.size.rds <- file.size(my.file.1)/1000000
file.size.fst <- file.size(my.file.2)/1000000

Após a execução, vamos verificar o resultado:

# results
my.formats <- c('.rds', '.fst')
results.read <- c(time.read.rds[3], time.read.fst[3])
results.write<- c(time.write.rds[3], time.write.fst[3])
results.file.size <- c(file.size.rds , file.size.fst)

# print text
my.text <- paste0('\nTime to WRITE dataframe with ',
                  my.formats, ': ',
                  results.write, ' seconds', collapse = '')
cat(my.text)

my.text <- paste0('\nTime to READ dataframe with ',
                  my.formats, ': ',
                  results.read, ' seconds', collapse = '')
cat(my.text)

my.text <- paste0('\nResulting FILE SIZE ',
                  my.formats, ': ',
                  results.file.size, ' MBs', collapse = '')
cat(my.text)
## 
## Time to WRITE dataframe with .rds: 0.643000000000001 seconds
## Time to WRITE dataframe with .fst: 0.0590000000000011 seconds
## Time to READ dataframe with .rds: 0.529 seconds
## Time to READ dataframe with .fst: 0.0560000000000009 seconds
## Resulting FILE SIZE .rds: 0.043855 MBs
## Resulting FILE SIZE .fst: 7.396082 MBs

A diferença é gritante! O formato fst não somente lê e grava com mais rapidez mas o arquivo resultante também é menor. A mensagem aqui é clara, quando estiver trabalhando com dados volumosos, dê preferência ao formato fst.

4.5 Arquivos SQLITE

O uso de arquivos csv, rds e fst para armazenar conjuntos de dados tem seus limites a medida que o tamanho dos arquivos aumenta e os dados fragmentam-se em várias tabelas. Se você está esperando muito tempo para ler apenas uma tabela de um arquivo com várias tabelas, deves procurar alternativas mais eficientes. Da mesma forma, se você estiver trabalhando em uma rede de computadores e muitas pessoas estão usando os mesmos dados, faz sentido manter e distribuir as informações de um servidor central. Dessa forma, cada usuário pode ter acesso à mesma informação, simultaneamente.

Isso nos leva ao tópico de programas de armazenamento e distribuição de banco de dados. Esses programas específicos geralmente funcionam com uma linguagem de consulta chamada SQL (Structured Query Language), e permitem ao usuário ler partes dos dados e mesmo manipulá-lo de forma eficiente. Existem muitas opções de software de banco de dados que se integra muito bem com R. A lista inclui mySQL, SQLite e MariaDB. Aqui, forneceremos um tutorial rápido sobre esse tópico usando o SQLite, que é o mais fácil de usar, uma vez que não precisa de nenhuma configuração do servidor e todos dados estão contidos em um único arquivo.

Antes de irmos para os exemplos, precisamos entender como se usa o software de banco de dados. Primeiro, um banco de dados deve existir em seu computador ou rede. Segundo, o R se conectará ao banco de dados e retornará um objeto de conexão. Com base nessa conexão, enviaremos consultas para importar dados desse banco de dados usando a linguagem SQL. A principal vantagem é que podemos ter um grande banco de dados de, digamos, 10 GB e carregar apenas uma pequena porção dele na área de trabalho do R. Essa operação também é muito rápida, permitindo um acesso eficiente às tabelas disponíveis.

4.5.1 Importação de Dados

Assumindo a existência de um arquivo com formato SQLite, podemos importar suas tabelas com o pacote RSQLite:

library(RSQLite)

# set name of SQLITE file
f.sqlite <- 'data/MySQLiteDatabase.SQLITE'

# open connection
my.con <- dbConnect(drv = SQLite(), f.sqlite)

# read table
my.df <- dbReadTable(conn = my.con,
                     name = 'MyTable1')

# print with str
glimpse(my.df)
## Rows: 100,000
## Columns: 2
## $ x <dbl> 0.98961356, 0.86569998, 0.01347851, 0.41680843,…
## $ G <chr> "A", "B", "A", "A", "B", "A", "A", "A", "A", "B…

Outro exemplo do uso do SQLITE é com instruções de um comando SQL. Observe que, no código anterior, usamos função dbReadTable para obter o conteúdo de todas as linhas da tabela MyTable1. Agora, vamos usar o comando dbGetQuery para obter dados da tabela myTable2 apenas quando a coluna G é igual a A:

# set sql statement
my.SQL <- "select * from myTable2 where G='A'"

# get query
my.df.A <- dbGetQuery(conn = my.con, statement = my.SQL)

# disconnect from db
dbDisconnect(my.con)

# print with str
glimpse(my.df.A)
## Rows: 49,990
## Columns: 2
## $ x <dbl> 0.04730187, 0.28772665, 0.41309654, 0.32132315,…
## $ G <chr> "A", "A", "A", "A", "A", "A", "A", "A", "A", "A…

Funcionou, conforme esperado.

Nesse exemplo simples podemos ver como é fácil criar uma conexão com um banco de dados, recuperar tabelas e desconectar. Se você estiver trabalhando com dados volumosos, na minha opinião, qualquer banco de dados que ocupe mais de 50% da memória RAM do seu computador, vale a pena utilizar um software de banco de dados apropriado. Caso existir um servidor de banco de dados disponível em seu local de trabalho, eu recomendo fortemente aprender a conectar-se a ele e usar o idioma SQL para sua vantagem. Existem muitas outras maneiras de consultar e manipular dados usando SQL. Vários tutoriais estão disponíveis na internet.

4.5.2 Exportação de Dados

Como exemplo, vamos criar dois dataframes com dados aleatórios e salvar ambos em um arquivo SQLite usando pacote RSQLite.

library(RSQLite)

# set number of rows in df
N = 10^5

# create simulated dataframe
my.large.df.1 <- data.frame(x=runif(N),
                            G= sample(c('A','B'),
                                      size = N,
                                      replace = TRUE))

my.large.df.2 <- data.frame(x=runif(N),
                            G = sample(c('A','B'),
                                       size = N,
                                       replace = TRUE))

# set name of SQLITE file
f.sqlite <- 'data/MySQLiteDatabase.SQLITE'

# open connection
my.con <- dbConnect(drv = SQLite(), f.sqlite)

# write df to sqlite
dbWriteTable(conn = my.con, name = 'MyTable1', value = my.large.df.1)
dbWriteTable(conn = my.con, name = 'MyTable2', value = my.large.df.2)

# disconnect
dbDisconnect(my.con)

A saída TRUE de dbWriteTable indica que tudo ocorreu bem. Uma conexão foi aberta usando a função dbConnect e os dataframes foram escritos em um arquivo SQLITE chamado data/MySQLiteDatabase.SQLITE. É boa política de programação sempre se desconectar do banco de dados após a utilização. Fizemos isso com a função dbDisconnect.

4.6 Dados Não-Estruturados e Outros Formatos

O uso das funções de importação de arquivos nos formatos destacados anteriormente é suficiente na grande maioria das situações. Apesar disso, vale destacar que o R possui outras funções específicas para diferentes formatos. Isso inclui arquivos exportados de outros softwares, tal como SPSS, Matlab, entre vários outros. Se esse for o seu caso, sugiro um estudo aprofundado do pacote foreign (R Core Team 2015).

Em alguns casos nos deparamos com dados armazenados de uma forma não estruturada, tal como um texto qualquer. Pode-se importar o conteúdo de um arquivo de texto (linha por linha) através da função readLines. Veja a seguir:

# set ibov file
my.f <- 'data/Ibov.csv'

# read it
my.txt <- readLines(my.f)

# print contents
print(my.txt[1:5])
## [1] "\"ref.date\",\"price.close\""
## [2] "2010-01-04,70045"            
## [3] "2010-01-05,70240"            
## [4] "2010-01-06,70729"            
## [5] "2010-01-07,70451"

Nesse caso importou-se todo o conteúdo do arquivo Ibov.csv como um texto. Observe que cada linha desse arquivo virou um elemento de um vetor atômico da classe de caracteres. Se fosse necessário, é possível escrever uma rotina que processasse esse arquivo linha por linha, separando as colunas e isolando os valores numéricos.

Em algumas situações, é necessário exportar algum tipo de texto para um arquivo. Por exemplo: quando se precisa salvar o registro de um procedimento em um arquivo de texto; ou quando se precisa gravar informações em um formato específico não suportado pelo R. Esse procedimento é bastante simples. Junto à função cat, basta indicar um arquivo de texto para a saída com o argumento file. Todo texto alimentado na função cat será escrito no arquivo de texto. Veja a seguir:

# set file
my.f <- 'data/temp.txt'

# set char to file
my.str <- paste('Today is', Sys.Date(), '\n')

# write it
cat(my.str, file = my.f, append = FALSE)

Criamos um objeto de texto com uma mensagem sobre a data atual. Executamos a função cat com os argumentos file e append. Esse último sinaliza a opção de adicionar novos textos ao final do arquivo ou não. Podemos checar o resultado com a função readLines:

# print contents of my.f
print(readLines(my.f))
## [1] "Today is 2020-07-30 "

4.7 Selecionando o Formato

Após entendermos a forma de salvar e carregar dados de arquivos locais em diferentes formatos, é importante discutirmos sobre a escolha do formato. Caso possível, o usuário deve levar em conta três pontos nessa decisão:

  • velocidade de importação e exportação;
  • tamanho do arquivo resultante;
  • compatibilidade com outros programas e sistemas.

Na grande maioria das situações, o uso de arquivos csv satisfaz esses quesitos. Ele nada mais é do que um arquivo de texto que pode ser aberto, visualizado e importado em qualquer programa. Desse modo, fica muito fácil compartilhar dados com outros usuários. Além disso, o tamanho de arquivos csv geralmente não é exagerado. Em caso negativo, pode-se compactá-lo utilizando a função zip. Por esses motivos, o uso de arquivos csv para importações e exportações é preferível na grande maioria das situações.

Em casos específicos, onde estiver trabalhando com dados volumosos, sugiro o formato fst. Esse permite um acesso extremamente rápido aos dados. O lado negativo é que os dados perdem a sua portabilidade. No caso do trabalho envolver diversas tabelas ou acesso a pequenas porções dos dados em cada estágio da pesquisa, sugiro o uso de arquivos SQLite.

4.8 Exercícios

  1. Crie um dataframe com o código a seguir:
library(dplyr)

my.N <- 10000
my.df <- data_frame(x = 1:my.N,
                    y = runif(my.N))

Exporte o dataframe resultante para cada um dos cinco formatos destacados a seguir:

  • csv
  • rds
  • xlsx
  • fst
  • SQLITE

Qual dos formatos ocupou maior espaço na memória do computador? Podes verificar o tamanho dos arquivos no Windows Explorer, por exemplo. No R, função file.size realiza o mesmo serviço.

  1. Melhore o código anterior com a mensuração do tempo de execução necessário para gravar os dados nos diferentes formatos (veja exemplos no capítulo atual). Qual deles teve a gravação mais rápida?

  2. Defina o valor de my.N no código anterior para 1000000. Esta mudança modifica as respostas das duas últimas perguntas?

  3. No material do livro existe um arquivo de dados chamado IbovStocks_long.csv. Baixe o arquivo da página do livro e utilize função readr::read_csv para carregar o seu conteúdo. Utilize função glimpse para verificar o conteúdo dos dados importados. Quantas colunas e qual o nome de cada coluna da tabela?

  4. Na página da CVM é possível obter informações de todas as empresas atualmente listadas na bolsa em um arquivo disponível no link http://sistemas.cvm.gov.br/cadastro/SPW_CIA_ABERTA.ZIP. Utilizando o R, baixe o arquivo em seu computador, importe os dados diretamente usando readr::read_csv (a função importa diretamente de arquivo compactados, sem necessidade de descompactação explícita). Quantas empresas fazem parte da bolsa atualmente (verifique o número de linhas do dataframe com função nrow).

  5. DESAFIO - Na página a seguir:

http://bit.ly/2L04RxX

é possível baixar dados de cotações de fechamento de todos os instrumentos financeiros negociados na B3. Porém, os dados estão em um formato de coluna com tamanho fixo. Após ler o manual de importação disponível no endereço anterior, utilize as funções do readr para importar as informações do ano 2020 na sua sessão do R.

Referências

Dragulescu, Adrian A. 2014. Xlsx: Read, Write, Format Excel 2007 and Excel 97/2000/Xp/2003 Files. https://CRAN.R-project.org/package=xlsx.

Mirai Solutions GmbH. 2016. XLConnect: Excel Connector for R. https://CRAN.R-project.org/package=XLConnect.

Ooms, Jeroen. 2017. Writexl: Export Data Frames to ’Xlsx’ Format. https://CRAN.R-project.org/package=writexl.

R Core Team. 2015. Foreign: Read Data Stored by Minitab, S, Sas, Spss, Stata, Systat, Weka, dBase, ... https://CRAN.R-project.org/package=foreign.

Wickham, Hadley. 2016a. Readxl: Read Excel Files. https://CRAN.R-project.org/package=readxl.