2013-01-17 7 views
71

sto cercando di caricare questa brutta formato data-set nella mia sessione R: http://www.cpc.ncep.noaa.gov/data/indices/wksst8110.forLeggi larghezza fissa file di testo

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 

Finora, posso leggere le righe con

x = readLines(path) 

Ma il file mescola lo 'spazio bianco' con '-' come separatori, e io non sono un esperto di espressioni regolari. Apprezzo qualsiasi aiuto per trasformare questo in un frame di dati R bello e pulito. grazie!

+5

E dare un'occhiata a 'read.fwf' per leggere la correzione di lettura larghezza e larghezza di dati formattati. –

+0

Penso che sia un'idea migliore per elaborare ogni riga. Mescola i caratteri '-' con ''. – Fernando

+0

In alternativa, potresti dire white-space oppure - è solo un carattere, quindi prima sostituisci tutte le occorrenze multiple di uno spazio con un carattere di tabulazione, quindi dividi tutte le voci separate da tabulazioni - o lo spazio bianco. – GitaarLAB

risposta

157

Si tratta di un file di larghezza fissa. Utilizzare read.fwf() per leggerla:

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 

Aggiornamento

Il pacchetto readr (rilasciato aprile 2015) fornisce un semplice e veloce alternativa.

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))) 

confronto Velocità: readr::read_fwf() era ~ 2x più veloce di utils::read.fwf().

+7

@Andrie come sapevi quali erano le larghezze e i salti? – Koba

+11

@Koba: ho copiato e incollato una delle righe in un editor di testo con un numero di colonne e ho contato manualmente le larghezze per ogni colonna (inclusi gli spazi bianchi quando richiesto). Inoltre puoi dire che devi saltare 4 linee intere prima di arrivare ai dati grezzi. – rayryeng

+5

@ La risposta di Pavithra in basso con larghezze di colonna negative per saltare gli spazi vuoti potrebbe essere più adatta per la risposta accettata. –

4

Io non so nulla di R, ma posso fornirvi un'espressione regolare che corrisponderà tali linee:

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

Un altro modo per determinare larghezze ...

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 
) 

La -1 nelle larghezze argomento dice che c'è una colonna di un carattere che deve essere ignorato, il -5 nelle larghezze argomento dice che c'è un colonna di cinque caratteri che deve essere ignorato, allo stesso modo ...

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

14

Prima di tutto, questa domanda è direttamente da un Coursera il corso "Carica dati e pulirlo" di porri. Mentre c'è un'altra parte della domanda, la parte difficile è la lettura del file.

Detto questo, il corso è principalmente destinato all'apprendimento.

Detesto la procedura di larghezza fissa di R. E 'lento e per gran numero di variabili, diventa molto rapidamente un dolore per negare alcune colonne, ecc

penso che è più facile da usare readLines() e poi da che uso substr() per rendere le variabili

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 
        ) 
+0

Questo approccio ha funzionato per me. Due ulteriori consigli: 1) puoi definire i dati personali solo come dati necessari. Quindi potrebbe essere semplice come 'mydata <- data.frame (var4 = substr (x, 29,32))' se hai solo bisogno della quarta colonna di dati. Inoltre, per gli utenti di Windows, Notepad ++ con il plug-in TextFX ti offre un righello di caratteri semplice e conteggiato in modo da poter capire cosa mettere in start e fermare i valori in 'substr'. Nota, tuttavia, che il valore di stop è uno più della posizione dell'ultimo carattere che vuoi conservare. – globalSchmidt

0

Il modo più diretto è usare read.fwf come indicato sopra.

Bene se l'obiettivo finale è quello di inserirlo in R, è sempre possibile leggerlo in Excel per iniziare, utilizzare la funzione "testo in cloumn" per ritagliare visivamente le colonne, quindi salvare il file finale come CSV . Successivamente, leggi il CSV in R.

0

Un metodo facile, se per i non programmatori (che sono disposti ad andare al di fuori di R)

  1. aprire la pagina in un browser web.
  2. Copia e incolla le righe di dati in un editor di testo. Ometti le intestazioni delle colonne.
  3. Usa ricerca e sostituisci per cambiare più spazi con un unico spazio (sostituisci spazio-spazio per spazio. Continua a fare clic finché non ci sono spazi rimanenti. Richiede pochi secondi).
  4. Utilizzare search-and-replace per sostituire il trattino (-) con uno spazio
  5. Per utilizzare la funzione di ricerca e sostituzione per sostituire lo spazio con virgola-spazio.

Ora avete un file .csv che è anche facile da leggere per un essere umano; salvarla. Caricarlo in Excel, R o altro, e continuare con l'elaborazione.

5

I documento here l'elenco di alternative per la lettura di file a larghezza fissa in R, oltre a fornire alcuni benchmark per i quali è più veloce.

Il mio approccio preferito è combinare fread con stringi; E 'competitiva come l'approccio più veloce, e ha il vantaggio (IMO) di memorizzare i dati come 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 = "\n" 
)[, 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 

Nota che fread automaticamente strisce spazi iniziali e finali - a volte, questo non è auspicabile, nel qual caso impostare strip.white = FALSE.

Nota anche che ho scelto sep = "\n" per impedire la suddivisione in linea. Se è implementato this issue, avremo un'alternativa più robusta.


potremmo anche hanno iniziato con un vettore di larghezze di colonna ww facendo:

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 abbiamo potuto scelto le colonne da escludere più robusto utilizzando indici negativi come:

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)) 

Quindi sostituire col_ends$beg[ii] con abs(col_ends$beg[ii]) e in la riga successiva:

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

Infine, se si desidera che i nomi delle colonne da leggere programatically così, si potrebbe pulire con 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 != ""] 

(si noti che la combinazione di questo passo con fread richiederebbe la creazione di una copia della tabella per rimuovere la riga di intestazione e sarebbe quindi inefficiente per i set di dati di grandi dimensioni)