9.4 Arquivos texto

Dados armazenados em um arquivo de texto puro ou simples podem ser facilmente importados no .

O formato mais comum de armazenar dados é o retangular, ou seja, uma tabela de dados com as observações ao longo das linhas e as variáveis ao longo das colunas. As vezes as variáveis são referentes a locais diferentes em cada linha.

Os valores de cada coluna de uma linha são separados por um caractere separador: vírgula, espaço, tab e etc; as linhas são separadas por quebras de linha (\n no Linux, \r\n no Windows).

Dados em arquivo texto podem conter caracteres latinos, como palavras com acentos no caso do Português. Para lidar com esta peculiaridade, as funções de importação de dados, possuem um argumento relacionado a codificação (encoding) dos caracteres. Arquivos texto em Português geralmente usam a codificação ISO 8859-1 ou equivalente Latin1. Portanto, para importação com formatação correta de caracteres latinos a especificação com esta codificação deve ser explícita.

O R utiliza o alfabeto Unicode para identificação de caracteres. Para associação unívoca de cada caractere (de mais 1 milhão de caracteres do alfabeto Unicode) a uma sequência de bits, o R usa o esquema de codificação UTF-8. Assim, recomenda-se utilizar essa codificação de caracteres como padrão em seus códigos e na construção e aquisição de dados. No RStudio a especificação da codificação de caracteres pode ser feita através do menu: *Tools ▶ Global Options ▶ Code ▶ Saving ▶ Default Text Encoding*.

9.4.1 rio

O pacote rio, nas palavras do próprio autor do pacote é "um canivete suíço para entrada e saída de dados" nos formatos mais frequentemente usados.

A grande funcionalidade do rio é simplificar estes processos que podem confundir a cabeça de quem está aprendendo R, devido a vastidão de opções disponíveis no (veja o Manual de Importação e Exportação do R).

Esta facilidade deve-se as premissas feitas pelo rio sobre o formato do arquivo. Ao importar um arquivo o pacote descobre o formato (pela extensão) e então aplica a função apropriada para ler aquele formato.

Desta forma, com o rio, você precisa saber duas funções para ler e escrever uma variedade de formatos de arquivos (Tabela 9.1): import() e export(), respectivamente.

Os formatos importados e exportados pelo rio são apresentados na Tabela 9.1. Para uma versão completa desta tabela confira a vinheta do pacote.

Tabela 9.1: Versão resumida da tabela com os formatos suportados pelo pacote rio.
Formato Extensão Pacote.de.importação Pacote.de.exportação Instalado.por..default.
Valores separados por vírgula .csv data.table data.table Sim
dados separados por tab .tsv data.table data.table Sim
Excel .xls readxl Sim
Excel .xlsx readxl openxlsx Sim
objetos salvos no R .RData, .rda base base Sim
objetos do R serializados .rds base base Sim
dados Fortran Sem extensão reconhecida utils Sim
Formato de dados com largura fixa .fwf utils utils Sim
Feather R/Python interchange format .feather feather feather Não
Armazenamento rápido (Fast Storage) .fst fst fst Não
JSON .json jsonlite jsonlite Não
Matlab .mat rmatio rmatio Não
Planilha OpenDocument .ods readODS readODS Não
tabelas HTML .html xml2 xml2 Não
documentos XML .xml xml2 xml2 Não
Área de transferência default é tsv clipr clipr Não

9.4.1.1 Como usar

Vamos baixar um arquivo de dados em formato texto para importá-lo com o pacote rio. Os dados são de precipitação diária e foram obtidos no sistema hidroweb da Agência Nacional das Águas.

A extensão do arquivo é .TXT e não se encaixa em nenhuma das extensões esperadas pelo rio. Mas se você visualizar o arquivo no navegador (browseURL(url="https://raw.github.com/lhmet/adar-ufsm/master/data/CHUVAS.TXT")) perceberá que os dados estão estruturados como CSV2, ou seja, com valores delimitados por ";" e o separador decimal ",".

Vamos então baixar o arquivo e salvá-lo em diretório temporário do computador.

# arquivo de exemplo disponível no GitHub
hw_url <- "https://raw.github.com/lhmet/adar-ufsm/master/data/CHUVAS.TXT"
# arquivo temporário para salvar o aquivo baixado
(hw_file <- tempfile(fileext = ".csv"))
# você pode substituir tempfile() por um caminho do seu
# computador, p.ex. "~/Downloads/CHUVAS.TXT"
download.file(
  url = hw_url_file, 
  destfile = hw_file
)
hw_file

Agora podemos importar os dados de precipitação baixados.

# Importa o arquivo 
dprec <- import(hw_file, 
                # se fread = TRUE (default usa função fread do pacote data.table)
                fread = FALSE,  
                skip = 15, # pula linhas com metadados
                header = TRUE, # com cabeçalho
                sep = ";", # delimitador entre os valores
                dec = ",", # separador decimal
                na.strings = "") # rótulo para dados faltantes
# primeiras 10 colunas e linhas dos dados
head(dprec[, 1:10])

Para saber quais argumentos devem ser especificados na função import() você precisar ler a documentação de ajuda da função (?import), principalmente a sessão Details. Os argumentos usados no exemplo acima, estão implícitos no a rgumento da função import() representado pela reticência (...). Conforme descrito na sessão Details, o parâmetro fread = FALSE implica no uso da função read.table() da base do R (descrita no Apêndice B.4) para importar o arquivo; então a descrição dos argumentos especificados encontra-se na ajuda da função read.table(), facilmente acessada pelo link na ajuda da função import.

Quando os nomes dos arquivos incluem uma extensão reconhecida pelo rio (Tabela 9.1), não há necessidade de especificar o argumento format nas funções import() e export(). O formato dos arquivos é inferido da extensão do arquivo (csv, no exemplo acima). No exemplo acima, a extensão do arquivo original do site é desconhecida (ex.: ".TXT", ".dat", etc). Nesta situação você deve especificar o formato do arquivo através do argumento format da import().

Para exportar os dados importados anteriormente, vamos criar um nome para salvar o arquivo com a função export(). Vamos salvá-lo usando um formato diferente do original, como tsv (valores separados por tab), para explorar a funcionalidade do rio.

# exporta para arquivo texto separado por tab
(arq_temp <- tempfile())
(dprec_file <- paste0(arq_temp, ".tsv"))
export(dprec, file = dprec_file, na = "-999")

9.4.1.2 Arquivos formatados com largura fixa

Alguns arquivos texto com dados tabulares podem não conter separadores para economizar espaço de disco. Outros arquivos podem ser formatados usando largura fixa para reservar o espaço de cada variável, o que facilita a legibilidade dos dados.

Vamos usar como exemplo o arquivo de dados do Índice de Oscilação Sul (SOI) obtido no site do National Weather Service - Climate Prediction Center (NWS-CPC).

# link para os dados do SOI
link_soi <- "http://www.cpc.ncep.noaa.gov/data/indices/soi"

Vamos visualizar os dados SOI no navegador para reconhecer o formato.

browseURL(url = link_soi)

Ao inspecionar cuidadosamente os dados até o fim da página no navegador, percebe-se os seguintes aspectos sobre estes dados:

  • temos duas tabelas de dados do SOI, uma de anomalias absolutas (da linha 4 até 74) e outra de anomalias normalizadas (da linha 79 à 148);

  • os valores da coluna YEAR ocupam 4 campos (ou espaços), ou seja, vão desde a 1ª até a 4 coluna; os valores da coluna JAN ocupam os campos da 5ª à 10ª coluna e este padrão é repetido para as colunas restantes.

  • dados faltantes são representados pelo rótulo -999.9

  • os dados incluem os nomes das variáveis (cabeçalho)

  • o cabeçalho ocupa um número de campos diferentes daqueles ocupados pelos valores de SOI (note o sinal de menos que antecede os valores)

Nosso interesse é na 1ª tabela de dados. Uma estratégia possível de importar estes dados é começar lendo o cabeçalho.

nome_vars <- scan(
    link_soi, # varredura do arquivo
    what = "character", # tipo dos dados
    skip = 3, # pula 3 linhas
    nmax = 13 # num. max. de campos a serem lidos
)
nome_vars

A seguir, podemos usar o cabeçalho obtido acima, como argumento na import() através do argumento col.names. As informações da inspeção dos dados são utilizadas para definir os outros argumentos.

soi <- import(
  file = link_soi,
  format = "fwf", # formato de largura fixa
  skip = 4, # pula 4 linhas
  header = FALSE, # sem cabeçalho
  nrows = 70, # num. de linhas
  widths = c(4, rep(6, 12)), # largura dos campos das variáveis
  na.strings = "-999.9", # string para dados faltantes
  col.names = nome_vars
)
str(soi)
tail(soi)

A documentação de ajuda da função import() do rio nos diz que no arquivo acima foi usada a função read.fwf() do para ler os dados. Os argumentos usados foram:

  • format = "fwf" significa formato de largura fixa
  • skip = 4 especifica que os dados iniciam após as 4 primeiras linhas do arquivo
  • header = FALSE especifica que estamos lendo diretamente os dados
  • nrows = 70 é o número de linhas lidas desde o começo dos dados, isto é, 74 - 4.
  • widths = c(4, rep(6, 12)) especifica a largura dos campos das variáveis; 4 campos para 1ª coluna e 6 campos para as 12 colunas seguintes;
  • na.strings = "-999.9" indica o rótulo para os dados faltantes
  • col.names = nome_vars especifica o nome das variáveis que será usado no quadro de dados.

Por fim, salvaremos as anomalias absolutas do SOI em um arquivo CSV.

# nome para o arquivo CSV
(soi_file <- paste0(tempdir(), "SOI.csv"))
# exportação com rio
export(soi,
  file = soi_file,
  na = "-999.9"
)
# verificar se o arquivo foi gerado
file.exists(soi_file)

Vamos importar o arquivo SOI.csv através da função file.choose() (ou choose.file() no Windows) que permite selecionar o arquivo de forma iterativa.

# leitura de dados com escolha interativa do arquivo
soi.df <- import(file.choose(),
  # file.choose só é válido em sistema *unix
  # no windows é choose.file()
  header = TRUE,
  na.strings = "-999.9"
)

Navegue até o diretório do arquivo SOI.csv e clique duas vezes sobre o arquivo ele.

head(soi.df)

9.4.2 Arquivos texto não estruturados

Em alguns casos é necessário ler arquivos textos sem uma estrutura definida como no caso de arquivos delimitados. Se o arquivo não é bem estruturado é mais fácil ler cada linha de texto separadamente e depois decompor e manipular o conteúdo do texto. A função readLines() é adequada para isso. Cada linha é tratada como um elemento de um vetor do tipo character.

Vamos importar os dados do INMET, mas dessa vez vamos focar no cabeçalho, onde estão as informações da estação meteorológica.

Obtendo os dados

# arquivo de exemplo disponível no GitHub
bdmep_url_file <- "https://raw.githubusercontent.com/lhmet/adar-ufsm/master/data/83004.txt"
# leitura do cabecalho do arquivo de dados de uma estação do inmet
cab <- readLines(bdmep_url_file)
head(cab)
# somente linhas com coordenadas da estação
cab[5:7]
is.vector(cab[5:7])
# arranjando em coluna
cbind(cab[5:7])
# selecionando somente os dados e o nome das variáveis
cab[-c(1:15)][1:10]

A função writeLines() escreve os elementos do vetor de caracteres em um arquivo texto. Essa é uma forma de escrever os dados mantendo a formatação original dos dados.

# dados sem as linhas com metadados
dados_limpos <- cab[-c(1:15)]
# arquivo para salvar os dados limpos
file_83004_limpo <- paste0(tempfile(), ".txt")
# escrevendo dados limpos
writeLines(
  text =  dados_limpos, 
  con = file_83004_limpo
)