Ler arquivo de texto com largura fixa

Eu estou tentando carregar este dataset formatado feio na minha session R: http://www.cpc.ncep.noaa.gov/data/indices/wksst8110.for

Weekly SST data starts week centered on 3Jan1990 Nino1+2 Nino3 Nino34 Nino4 Week SST SSTA SST SSTA SST SSTA SST SSTA 03JAN1990 23.4-0.4 25.1-0.3 26.6 0.0 28.6 0.3 10JAN1990 23.4-0.8 25.2-0.3 26.6 0.1 28.6 0.3 17JAN1990 24.2-0.3 25.3-0.3 26.5-0.1 28.6 0.3 

Até agora, eu posso ler as linhas com

  x = readLines(path) 

Mas o arquivo mistura ‘espaço em branco’ com ‘-‘ como separadores, e eu não sou um especialista em regex. Eu aprecio qualquer ajuda em transformar isso em um bom e limpo quadro de dados. obrigado!

Este é um arquivo de largura fixa. Use read.fwf() para ler:

 x < - read.fwf( file=url("http://www.cpc.ncep.noaa.gov/data/indices/wksst8110.for"), skip=4, widths=c(12, 7, 4, 9, 4, 9, 4, 9, 4)) head(x) V1 V2 V3 V4 V5 V6 V7 V8 V9 1 03JAN1990 23.4 -0.4 25.1 -0.3 26.6 0.0 28.6 0.3 2 10JAN1990 23.4 -0.8 25.2 -0.3 26.6 0.1 28.6 0.3 3 17JAN1990 24.2 -0.3 25.3 -0.3 26.5 -0.1 28.6 0.3 4 24JAN1990 24.4 -0.5 25.5 -0.4 26.5 -0.1 28.4 0.2 5 31JAN1990 25.1 -0.2 25.8 -0.2 26.7 0.1 28.4 0.2 6 07FEB1990 25.8 0.2 26.1 -0.1 26.8 0.1 28.4 0.3 

Atualizar

O pacote readr (lançado em abril de 2015) fornece uma alternativa simples e rápida.

 library(readr) x < - read_fwf( file="http://www.cpc.ncep.noaa.gov/data/indices/wksst8110.for", skip=4, fwf_widths(c(12, 7, 4, 9, 4, 9, 4, 9, 4))) 

Comparação de velocidade: readr::read_fwf() foi ~ 2x mais rápido que utils::read.fwf () .

Outra maneira de determinar larguras …

 df < - read.fwf( file=url("http://www.cpc.ncep.noaa.gov/data/indices/wksst8110.for"), widths=c(-1, 9, -5, 4, 4, -5, 4, 4, -5, 4, 4, -5, 4, 4), skip=4 ) 

O argumento -1 no width diz que há uma coluna de um caractere que deve ser ignorada, o -5 no argumento widths diz que há uma coluna de cinco caracteres que deve ser ignorada, da mesma forma ...

ref: https://www.inkling.com/read/r-cookbook-paul-teetor-1st/chapter-4/recipe-4-6

Em primeiro lugar, essa pergunta é diretamente de um curso do Coursera “Get Data and Clean It” da Leeks. Embora haja outra parte da questão, a parte difícil é ler o arquivo.

Dito isto, o curso é principalmente destinado a aprendizagem.

Eu odeio o procedimento de largura fixa de R. É lento e, para um grande número de variables, rapidamente se torna uma dor negar certas colunas, etc.

Eu acho que é mais fácil usar readLines() e depois disso usar substr() para fazer suas variables

 x < - readLines(con=url("http://www.cpc.ncep.noaa.gov/data/indices/wksst8110.for")) # Skip 4 lines x <- x[-(1:4)] mydata <- data.frame(var1 = substr(x, 1, 10), var2 = substr(x, 16, 19), var3 = substr(x, 20, 23), var4 = substr(x, 29, 32) # and so on and so on ) 

Agora você pode usar a function read_fwf() no pacote readr Hadley Wickham.

Uma enorme melhoria de desempenho é esperada, em comparação com a base read.fwf() .

Eu documentei aqui a lista de alternativas para a leitura de arquivos de largura fixa em R, além de fornecer alguns benchmarks para os quais é mais rápido.

Minha abordagem preferida é combinar fread com stringi ; é competitivo como a abordagem mais rápida e tem o benefício adicional (IMO) de armazenar seus dados como um data.table :

 library(data.table) library(stringi) col_ends < - list(beg = c(1, 10, 15, 19, 23, 28, 32, 36, 41, 45, 49, 54, 58), end = c(9, 14, 18, 22, 27, 31, 35, 40, 44, 48, 53, 57, 61)) data = fread( "http://www.cpc.ncep.noaa.gov/data/indices/wksst8110.for", header = FALSE, skip = 4L, sep = NULL )[, lapply(1:(length(col_ends$beg)), function(ii) stri_sub(V1, col_ends$beg[ii], col_ends$end[ii])) ][ , paste0("V", c(2, 5, 8, 11)) := NULL] # V1 V3 V4 V6 V7 V9 V10 V12 V13 # 1: 03JAN1990 23.4 -0.4 25.1 -0.3 26.6 0.0 28.6 0.3 # 2: 10JAN1990 23.4 -0.8 25.2 -0.3 26.6 0.1 28.6 0.3 # 3: 17JAN1990 24.2 -0.3 25.3 -0.3 26.5 -0.1 28.6 0.3 # 4: 24JAN1990 24.4 -0.5 25.5 -0.4 26.5 -0.1 28.4 0.2 # 5: 31JAN1990 25.1 -0.2 25.8 -0.2 26.7 0.1 28.4 0.2 # --- # 1365: 24FEB2016 27.1 0.9 28.4 1.8 29.0 2.1 29.5 1.4 # 1366: 02MAR2016 27.3 1.0 28.6 1.8 28.9 1.9 29.5 1.4 # 1367: 09MAR2016 27.7 1.2 28.6 1.6 28.9 1.8 29.6 1.5 # 1368: 16MAR2016 27.5 1.0 28.8 1.7 28.9 1.7 29.6 1.4 # 1369: 23MAR2016 27.2 0.9 28.6 1.4 28.8 1.5 29.5 1.2 

Observe que o fread automaticamente os espaços em branco fread e finais - às vezes, isso é indesejável, e nesse caso defina strip.white = FALSE .


Também poderíamos começar com um vetor de larguras de colunas, fazendo:

 ww < - c(9, 5, 4, 4, 5, 4, 4, 5, 4, 4, 5, 4, 4) nd <- cumsum(ww) col_ends <- list(beg = c(1, nd[-length(nd)]+1L), end = nd) 

E poderíamos ter escolhido quais colunas excluir de forma mais robusta usando índices negativos como:

 col_ends < - list(beg = c(1, -10, 15, 19, -23, 28, 32, -36, 41, 45, -49, 54, 58), end = c(9, 14, 18, 22, 27, 31, 35, 40, 44, 48, 53, 57, 61)) 

Em seguida, substitua col_ends$beg[ii] com abs(col_ends$beg[ii]) e na linha seguinte:

 paste0("V", which(col_ends$beg < 0)) 

Por último, se você quiser que os nomes das colunas também sejam programados, você pode limpar com readLines :

 cols < - gsub("\\s", "", sapply(1:(length(col_ends$beg)), function(ii) stri_sub(readLines(URL, n = 4L)[4L], col_ends$beg[ii]+1L, col_ends$end[ii]+1L))) cols <- cols[cols != ""] 

(note que combinar essa etapa com fread exigiria a criação de uma cópia da tabela para remover a linha de header e, portanto, seria ineficiente para grandes conjuntos de dados)

Eu não sei nada sobre o R, mas posso fornecer uma regex que corresponda a essas linhas:

 \s[0-9]{2}[AZ]{3}[0-9]{4}(\s{5}[0-9]+\.[0-9]+[ -][0-9]+\.[0-9]+){4} 

A maneira mais direta é usar read.fwf como apontado acima.

Bem, se o objective final é colocá-lo em R, você sempre pode lê-lo no Excel para começar, use o recurso “text to cloumns” para recortar visualmente as colunas e salve o arquivo final como CSV. Depois disso, leia o CSV em R.

Um método fácil se para não-programadores (que estão dispostos a sair de R)

  1. Abra a página em um navegador da web.
  2. Copie e cole as linhas de dados em um editor de texto. Omitir headers de coluna.
  3. Use a pesquisa e substituição para alterar vários espaços com um único espaço (Substitua espaço por espaço. Continue clicando até que não haja espaços duplos à esquerda. Leva apenas alguns segundos).
  4. Use a pesquisa e substituição para replace o traço (-) por um espaço
  5. ForUse search-and-replace para replace o espaço por vírgula espacial.

Agora você tem um arquivo .csv que também é fácil para um ser humano ler; Salve isso. Carregue-o no Excel, R ou qualquer outro e continue com o processamento.