3.4 Importando e exportando dados no R

ATENÇÃO! Se você utiliza Windows, e no seu gerenciador de arquivos os arquivos aparecem sem extensão (.csv, .txt, .doc etc.), mude nas suas preferências para não ocultar extensões de arquivos conhecidos. Dessa forma você consegue ver os arquivos pelo tipo (extensão).

Existem diversas funções para importar dados para objetos do R, incluindo funções para ler arquivos do Excel (.xls, ou .xlsx), arquivos XML, arquivos *.DBF etc. O R também tem pacotes que interagem diretamente com bancos de dados (mysql, postgres, sql etc.). Não cobriremos a importação desses tipos aqui, mas você pode pesquisar sozinho no rede.

É frequente encontrarmos problemas de acentuação e na transferibilidade entre sistemas operacionais diferentes (Mac, Linux, Windows). A palavra chave aqui é codificação de caracteres (em inglês, “character encoding”).

3.4.1 Arquivos de texto simples para estocar dados

Muitos dados que obtemos online e os próprios scripts do R são do formato mais simples que existe, que são arquivos de texto, geralmente arquivos salvos com extensões .csv ou .txt. Arquivos desse tipo podem ser abertos em qualquer editor de texto, em qualquer sistema operacional e em qualquer versão. Isso garante arquivamento, longevidade e transferibilidade. Portanto, é a melhor forma de salvar seus dados e compartilhá-los.

Qualquer arquivo desse tipo pode ser lido pelos os editores de script do R ou RStudio. Pode também exportar planilhas do Excel ou LibreOffice (e afins) para esse formato. Vamos nos concentrar neste curso em lidar com arquivos deste tipo.

É importante atentar em arquivos de texto contendo dados tabulados para:

  • O separador das colunas pode ser ;, tabulação (no R = ’‘’), ,, ou qualquer símbolo que indique a separação das colunas (ou seja não está nas células);

  • Casas decimais podem ser separadas por . ou ,.

DICA: Procure saber como seus dados estão antes de tentar importá-los, de forma a indicar corretamente o delimitador e o separador das casas decimais adequados. Você evitará assim muita dor de cabeça!

  • Datas - colunas com datas constituem um objeto de classe date no R, que a converte em número que pode ser usado em operações matemáticas. Dependendo de como seus dados estão formatados no original, é comum a inversão de mês com dia entre, por exemplo, o sistema inglês (MM-DD-YYYY) e o sistema português (DD-MM-YYYY). Tenha controle disso!

Por isso, recomenda-se que:

  • Defina um padrão que você sempre usará para formatar seus dados ANTES de importá-los ao R. Dessa forma você irá memorizar rapidamente como importar os dados do jeito que você sempre prepara;

  • Padronize a codificação dos caracteres (UTF8 é padrão Mac e Linux; Latin1 é padrão Windows) em arquivos .txt;

  • Padronize o separador de casa decimal (ponto ou vírgula?);

  • Pradonize a quebra de linha, i.e., o que indica no texto o início de uma nova linha (novamente, isso é diferente entre Mac, Linux e Windows);

  • Padronize se colunas de texto vão entre aspas;

  • Padronize como você dá nome às colunas; nome de colunas e de linhas não devem ser muito longos, e deve-se evitar acentos ou espaços em branco em nomes de colunas. Isso é muito importante!

  • Se você usa planilhas, recomendamos usar uma versão de software livre da família LibreOffice/OpenOffice pois eles permitem um maior controle da exportação dos dados, o que inclui controlar o tipo de codificação de caracter dos dados de saída e também separadores das colunas, tanto para ler como para salvar arquivos de planilhas.

3.4.2 Importando dados

3.4.2.1 Pacote base do R

A principal função para importar dados no R é read.table(). Ela funciona para importar arquivos em formato de texto simples (.csv, .txt).

Vamos utilizar um conjunto de dados contendo as coordenadas geográficas dos municípios brasileiros para praticar a importação dos dados. Baixe-o para a sua pasta de trabalho.

Em seguida, abra o arquivo com um editor de texto simples (Bloco de Notas, Notepad++, TextWrangler, gedit, etc.) e veja como ele está formatado. Verifique:

  • Qual é o separador de colunas?;

  • Qual é a codificação dos caracteres? (consegue ver e editar isso no seu editor?);

  • Qual é a quebra de linha? (consegue ver e editar isso no seu editor?

  • Aspas duplas ou simples definem colunas? (este arquivo não tem nenhuma aspas!)

Vamos agora abrir este arquivo no LibreOffice (ou similar, como o Excel). Busque os comandos de importação para poder importar o arquivo de texto2. Veja os controles na importação quanto aos elementos acima:

  • Salve o arquivo como *.ods;

  • Salve novamente como *.csv - veja como você tem controle na exportação quanto aos elementos acima.

# se você colocou o arquivo na sua pasta de trabalho, ele deve estar visível por
dir(pattern = "csv")
# então posso ler sem precisar especificar o caminho até o arquivo
# veja o help da função antes de começar
?read.table
# os seguintes argumentos são mais importantes:
# sep = " " #o codigo que separa as colunas, o padrão é espaço
# quote = "\"'"  #o que define células de texto - o padrão é interpretar tanto aspa simples como dupla presentes
# dec = "." #ponto é a casa decimal padrão
# header = FALSE #a primeira linha não tem o nome de colunas
# as.is = FALSE #o padrão é converter texto em fatores, se usar T não fará isso
# na.strings #se definir, pode informar aqui que símbolos em células inteiras que sejam interpretados como valores ausentes (NA)
# encoding #codificação da acentuação. o padrão é 'unknown' (desconhecido), na qual ele reconhece segundo o sistema operacional. As opções mais usadas são 'latin1' ou 'utf8' e alterne com isso se você tem problemas com acentos.
# o arquivo original tem os seguintes formatos:
# colunas separadas por tabulação (no R isso é definido pela expressão regular "\t")
# decimal com ponto
# não tem aspas definindo as colunas de texto.
# a primeira linha é o nome das colunas.
# Então, para ler posso usar:
dd <- read.table(file = "municipiosbrasil.csv", sep = "\t", header = T)
class(dd) # data.frame
dim(dd) # dimensão do objeto
head(dd) # cabeçalho do data.frame

# veja o que aconteceria se eu achasse que no meu arquivo as colunas são separadas por vírgula
dd2 <- read.table(file = "municipiosbrasil.csv", sep = ",", header = T)
head(dd2)
dim(dd2) # apenas 1 coluna, porque o separador informado não é o mesmo dos dados

# e se o encoding do meu arquivo estiver errado?
dd3 <- read.table(file = "municipiosbrasil.csv", sep = "\t", header = T, encoding = "latin1")
dd3[5562, ] # veja o que aconteceu com os acentos nessa linha
dd[5562, ] # no original o encoding não é "latin1"

# veja a estrutura do objeto correto
str(dd)
# Poxa, todas as colunas são fatores, mesmo as colunas Latitude e Longitude que são numéricas.
# Deve ter algum valor nessas colunas que não são numéricos.
# Quais são?
vl <- is.na(as.numeric(as.vector(dd$Latitude))) # quais são NA quando eu converto para numérico? Pois esses devem ser valores de texto e não numéricos. Note que converti o fator para vetor antes de converter para numérico. A função is.na pergunta o que é NA, pois os textos que não podem ser convertidos para número serão valores ausentes (NA)
sum(vl)
dd[vl, ] # essas linhas tem a palavra "NULL" para Latitude e Longitude no arquivo original (volte lá para confirmar), e o R não reconheceu isso como ausente NA. Como vetores devem ser da mesma classe, os números dessas colunas foram codificados como texto e as colunas convertidas a fatores de texto que é o padrão da função read.table()

Podemos usar o argumento na.strings para corrigir isso durante a importação:

dd4 <- read.table(file = "municipiosbrasil.csv", sep = "\t", header = T, dec = ".", na.strings = c("NULL", "NA", ""))
# qualquer CELULA INTEIRA que contenha NULL ou NA ou esteja vazia SERÁ INTERPRETADA COMO VALOR AUSENTE e codificada como NA no R.
str(dd4)
# note que agora as colunas Latitude e Longitude foram interpretadas como número

# mas o que acontece se informamos mal a casa decimal?
dd5 <- read.table(file = "municipiosbrasil.csv", sep = "\t", header = T, dec = ",", na.strings = c("NULL", "NA", ""))
str(dd5)
# como tem ponto como definição de casa decimal no arquivo de dados, as colunas numéricas foram novamente interpretadas como texto.

# Texto como vetores ou fatores?
dd4 <- read.table(file = "municipiosbrasil.csv", sep = "\t", header = T, dec = ".", na.strings = c("NULL", "NA", ""))
str(dd4) # todas as colunas de texto neste objeto foram interpretadas como fatores
# o argumento as.is permite corrigir isso. "as is" significa "como está" nos dados originais, então valores de texto são lidos como vetores de caracteres não codificados em fatores.
dd6 <- read.table(
  file = "municipiosbrasil.csv",
  sep = "\t",
  header = T,
  dec = ".",
  na.strings = c("NULL", "NA", ""),
  as.is = TRUE
)
str(dd6) # diferentemente do objeto anterior, não há mais fatores
# Lembram que colocamos o endereco do arquivo mais acima?
# podemos usar um endereco da internet para baixar um arquivo
dd7 <-
  read.table(
    "https://github.com/LABOTAM/IntroR/blob/main/dados/municipiosbrasil.csv",
    sep = "\t",
    header = TRUE
  )
dd7
head(dd7)
# a função read.table tem vários outros argumentos. Veja o help e entenda isso bem.

3.4.2.2 Pacote readr

A principal função para ler arquivos do pacote readr (Wickham e Hester 2020) se chama read_delim(). Funciona de maneira parecida com o read.table() com algumas pequenas diferenças: não converte colunas de texto que possam ser categorizadas em fatores (read.table() faz isso por padrão), retorna um tibble no lugar de um data.frame (tibbles são data.frames diferentes na maneira como aparecem no console; além de mostrar apenas uma porção dos dados, para cada coluna há a indicação do tipo de variável presente), assume por padrão que o dado importado possui cabeçalho. Existem outras diferenças que podem ser melhor entendidas na página do pacote (https://github.com/tidyverse/readr). Os argumentos possuem nomes diferentes do que os utilizados em read.table() e, como este, importa arquivos em formato de texto simples (.csv , .txt).

# pacote readr
# usando como exemplo o mesmo arquivo municipiosbrasil.csv
library("readr")
rr1 <- read_delim("municipiosbrasil.csv", delim = "\t")
rr1
dd7
dim(rr1)
dim(dd7)

Como no pacote base, também podemos ler arquivos diretamente da rede:

rr2 <- read_delim("https://github.com/LABOTAM/IntroR/blob/main/dados/municipiosbrasil.csv", delim = "\t")
rr2

3.4.2.3 Pacote data.table

A principal função para ler arquivos do pacote data.table (Dowle e Srinivasan 2020) se chama fread(). Este pacote é muito conhecido devido à velocidade de suas ações, funcionando perfeitamente para dados grandes. Esta função possui uma particularidade: o usuário não precisa indicar o separador; automaticamente ele descobre o separador e lê o arquivo. Em casos especiais, é necessário a indicação do separador com o argumento sep, igual ao read.table(). Ao ler um arquivo, a função retorna também um data.frame, porém com certas particularidades quanto à impressão do resultado na tela do console, como acontece com a função read_delim() do pacote readr. Mais informações, leiam atentamente o site do pacote: https://github.com/Rdatatable/data.table. O pacote como um todo é uma excelente ferramenta na manipulação de dados. Como os pacotes citados acima, esta função é capaz de importar arquivos em formato de texto simples (.csv , .txt).

# pacote data.table
# usando como exemplo o mesmo arquivo municipiosbrasil.csv
library("data.table")
dt1 <- fread("municipiosbrasil.csv")
dt1

Também podemos ler arquivos diretamente da rede, providenciando um endereço que contenha um arquivo de texto simples:

dt2 <- fread("https://github.com/LABOTAM/IntroR/blob/main/dados/municipiosbrasil.csv")
dt2

3.4.2.4 Importando do Excel diretamente

Utilizamos o pacote readxl(Wickham e Bryan 2019) para ler dados de arquivos Excel, isto é, arquivos .xlsx ou .xls. A principal função para importar dados deste pacote se chama read_excel(). Os principais erros aqui podem ser por células unidas, cabeçalhos no topo da planilha, e acentos. Veja o ? das funções usadas para conhecer parâmetros opcionais para resolver esses possíveis problemas.

# instale o pacote
library("readxl")

# se o arquivo for xls
# Salve o arquivo municipiosbrasil.csv como xlsx ou xls
meuxlsx <- "municipiosbrasil.xlsx"
dd <- read_excel(path = meuxlsx, sheet = 1)
dd
dd <- as.data.frame(dd)
dd

# se o arquivo for xls
meuxls <- "municipiosbrasil.xls"
dd <- read_excel(path = meuxls, sheet = 1)
dd
dd <- as.data.frame(dd)
dd

3.4.3 Exportando dados

3.4.3.1 Pacote base do R

A principal função do pacote base do R para exportar dados se chama write.table(). Ela funciona para exportar arquivos em formato de texto simples (.csv, .txt) e usa basicamente os mesmos argumentos da função read.table().

?write.table # veja o help - recomendo usar essa função genérica e evitar de usar atalhos tipo write.csv, que no fundo usam esta mesma função

Por se tratar de uma função do pacote base, não é necessário recorrer a função library() para chamar nenhum pacote, pois a função encontra-se disponível a qualquer momento para ser utilizada no R:

# vamos usar o mesmo arquivo
dir(pattern = "csv")
# ler o arquivo para o R para ter algo a exportar
dd <- read.table(file = "municipiosbrasil.csv", sep = "\t", header = T, dec = ".", na.strings = c("NULL", "NA", ""), as.is = TRUE)
str(dd) # diferentemente do objeto anterior, não há mais fatores

# filtrando apenas para municipios do Amazonas:
vl <- dd$Province %in% "Amazonas"
sum(vl) # quantos são?
# ou, desse jeito que é identico:
vl <- dd$Province == "Amazonas"
sum(vl)
dd.am <- dd[vl, ]
nrow(dd.am) == sum(vl) # deve ser verdadeiro, certo?

# salvando esses dados num novo arquivo com diferentes formatações:
# separado por tabulação e textos sem aspas e células NA sem nada
write.table(dd.am, file = "muni-am1.csv", sep = "\t", na = "", quote = FALSE)
# separado por tabulação e textos com aspas e células NA sem nada
write.table(dd.am, file = "muni-am2.csv", sep = "\t", na = "", quote = TRUE)

# separado por vírgula e textos com aspas e células NA com a palavra valor.ausente
write.table(dd.am, file = "muni-am3.csv", sep = ",", na = "valor.ausente", quote = TRUE)

# separado por vírgula e textos com aspas e células NA vazios e não adicona nomes das linhas como primeira coluna (row.names=FALSE). Pode deslocar a primeira linha na sua planilha SE você NAO USAR este argumento)
write.table(dd.am, file = "muni-am4.csv", sep = ",", na = "", quote = TRUE, row.names = FALSE)

# separado por tabulação e textos sem aspas e células NA vazias, sem nomes das linhas, e quebra de linha no formato do windows (eol = "\r\n")
write.table(dd.am, file = "muni-am5.csv", sep = ",", na = "", quote = TRUE, row.names = FALSE, eol = "\r\n")

# ABRA OS ARQUIVOS GERADOS NO SEU EDITOR DE TEXTO E COMPARE AS FORMATAÇÕES GERADAS

3.4.3.2 Pacote readr

A principal função do pacote readrpara exportar dados se chama write_delim(). Ela exporta data.frames em formato de texto simples (.csv, .txt), utilizando basicamente os mesmos argumentos da função read_delim(), pertencente ao mesmo pacote.

# exportando dados com pacote readr
# utilizando mesmo objeto criado com pacote base
write_delim(dd.am, "muni-am6.csv", delim = "\t")
write_delim(dd.am, "muni-am7.csv", delim = ";")

3.4.3.3 Pacote data.table

A principal função do pacote data.table para exportar data.frames em formato de texto simples (.csv, .txt) se chama fwrite() e usa basicamente os mesmos argumentos da função read_delim(), pertencente ao pacote readr.

# exportando dados com pacote data.table
# utilizando mesmo objeto criado com pacote base
fwrite(dd.am, "muni-am8.csv", sep = "\t")

3.4.4 Outras funções úteis

A função scan() lê um arquivo de texto em qualquer formato para um vetor ou lista no R. Trata-se de uma função genérica que é bom memorizar. Vamos usar o mesmo arquivo municipiosbrasil.csv para demonstrar sua utilidade:

# esta função é muito util para ler linha por linha um arquivo de texto que você quer explorar.
dd <- scan(file = "municipiosbrasil.csv", what = "complex", sep = "\n")
class(dd)
## [1] "character"
length(dd) # cada linha é um elemento do vetor
## [1] 5568
dd[1]
## [1] "Country\tProvince\tRegiao\tMunicipio\tLatitude\tLongitude"
# usando tabulação
dd2 <- scan(file = "municipiosbrasil.csv", what = "complex", sep = "\t")
class(dd2)
## [1] "character"
length(dd2) # cada célula é um elemento deste vetor
## [1] 33408
dd2[1:5]
## [1] "Country"   "Province"  "Regiao"    "Municipio" "Latitude"
# nao faz muito sentido com esses dados que tem formato de tabela, mas essa função pode ser usada com qualquer arquivo de tipo texto, por exemplo:
# de um artigo no qual você quer buscar palavras e tabular palavras chaves?
# num log de uma análise feita por outro software (nao no R) do qual você quer extrair resultados a partir da lógica complicada do texto de resultado)
# etc.

Referências

Dowle, Matt, e Arun Srinivasan. 2020. data.table: Extension of ‘data.frame‘. https://CRAN.R-project.org/package=data.table.
Wickham, Hadley, e Jennifer Bryan. 2019. readxl: Read Excel Files. https://CRAN.R-project.org/package=readxl.
Wickham, Hadley, e Jim Hester. 2020. readr: Read Rectangular Text Data. https://CRAN.R-project.org/package=readr.

  1. Isso é mais fácil de ser feito no LibreOffice/OpenOffice↩︎