2013-01-17 20 views
71

Próbuję załadować ten brzydki sformatowany zbiór danych do mojego R sesji: http://www.cpc.ncep.noaa.gov/data/indices/wksst8110.forCzytaj stałej szerokości plik tekstowy

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 

Dotychczas można odczytać linie z

x = readLines(path) 

Ale plik miesza "białe spacje" z "-" jako separatorami i nie jestem ekspertem od wyrażeń regularnych. Doceniam każdą pomoc w przekształceniu tego w ładną i czystą ramkę danych R. dzięki!

+5

I spójrz na 'read.fwf', aby przeczytać read fix ed formatowane dane. –

+0

Myślę, że lepiej przetwarzać każdy wiersz. Łączy "-" z "" znakami. – Fernando

+0

Można też powiedzieć, że białe znaki lub - to tylko jeden znak, więc najpierw zamień wszystkie wielokrotne wystąpienia spacji na znak tabulacji, a następnie podziel wszystkie wejścia oddzielone tabulatorami - lub białe znaki. – GitaarLAB

Odpowiedz

157

Ten plik jest stałą szerokość. Użyj read.fwf() aby ją przeczytać:

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 

Aktualizacja

Pakiet readr (wydany kwietnia 2015) zapewnia prostą i szybką alternatywę.

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

porównanie Speed: readr::read_fwf() było ~ 2x szybciej niż utils::read.fwf().

+7

@Andrie skąd wiesz, jakie były szerokości i pominięcia? – Koba

+11

@Koba: Kopiowałem i wklejałem jedną z linii do edytora tekstu, który miał liczbę kolumn i ręcznie policzyłem szerokości każdej kolumny (łącznie z białymi znakami, gdy jest to wymagane). Możesz również powiedzieć, że musisz pominąć 4 całe linie, zanim dotrzesz do nieprzetworzonych danych. – rayryeng

+5

@ Odpowiedź firmy Pavithra poniżej z ujemnymi szerokościami kolumn dla pomijania niechcianych białych znaków może być lepiej dopasowana do zaakceptowanej odpowiedzi. –

4

nie wiem nic o R, ale mogę zapewnić Państwu regex, który będzie pasował takie linie:

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

Innym sposobem określenia szerokości ...

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 
) 

-1 w szerokościach teza mówi, że jest to jedna kolumna znaków, które powinny być ignorowane, -5 w szerokościach teza mówi, że nie jest kolumna pięć znaków, które powinny być ignorowane, podobnie ...

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

14

pierwsze, że pytanie jest bezpośrednio z Coursera „uzyskać dane i oczyścić” oczywiście przez porem. Podczas gdy jest inna część pytania, trudną częścią jest czytanie pliku.

To powiedziawszy, kurs jest głównie przeznaczony do nauki.

Nienawidzę procedury stałej szerokości R. Jest powolny i dla dużej liczby zmiennych, to bardzo szybko staje się ból zanegować pewne kolumny itp

myślę, że łatwiejsze w użyciu readLines() a następnie od tego zastosowania substr() aby zmienne

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

To podejście zadziałało dla mnie. Dwie dodatkowe wskazówki: 1) możesz zdefiniować mydata, aby była tylko potrzebnymi danymi. Może to być tak proste, jak 'mydata <- data.frame (var4 = substr (x, 29, 32)), jeśli potrzebujesz tylko czwartej kolumny danych. Ponadto, dla użytkowników Windows, Notepad ++ z wtyczką TextFX dostarczy ci prostą i prostą linijkę linijki, dzięki czemu będziesz mógł dowiedzieć się, co umieścić w wartościach początkowych i końcowych w 'substr'. Zauważ jednak, że wartość zatrzymania jest o jeden więcej niż pozycja ostatniego znaku, który chcesz zachować. – globalSchmidt

0

Najbardziej bezpośrednim sposobem jest użycie read.fwf, jak wskazano powyżej.

Cóż, jeśli ostatecznym celem jest wprowadzenie go do R, zawsze można go najpierw przeczytać w Excelu, użyć funkcji "text to cloumns", aby wizualnie wyciąć kolumny, a następnie zapisać ostateczny plik jako CSV . Po tym przeczytaj CSV do R.

0

prosta metoda, jeśli dla nie-programistów (którzy są gotowi, aby przejść poza R)

  1. otworzyć stronę w przeglądarce internetowej.
  2. Skopiuj i wklej linie danych do edytora tekstu. Pomiń nagłówki kolumn.
  3. Użyj funkcji "znajdź i zamień", aby zmienić wiele spacji pojedynczą spacją (Zamień spację, spacją i przytrzymaj Klikaj, dopóki nie pozostaną podwójne spacje . Trwa tylko kilka sekund).
  4. Użyj funkcji "znajdź i zamień", aby zastąpić myślnik (-) spacją:
  5. ForUse wyszukaj i zamień, aby zastąpić spację przecinkiem.

Masz teraz plik .csv, który jest również łatwy do odczytania przez człowieka; Zapisz to. Załaduj go do Excela, R lub cokolwiek i kontynuuj przetwarzanie.

5

I dokumentuje here listę alternatyw dla odczytywania plików o stałej szerokości w R, a także zapewnia niektóre punkty odniesienia, dla których jest najszybszy.

Moje preferowane podejście polega na połączeniu fread z stringi; jest konkurencyjny jak najszybszym podejściem i ma dodatkową zaletę (IMO) przechowywania danych jako 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 

Zauważ, że fread automatycznie Paski początkowe i końcowe spacje - czasami jest to niepożądane, w takim przypadku ustaw strip.white = FALSE.

Pamiętaj też, że wybrałem opcję sep = "\n", aby zapobiec podziałowi wewnątrz linii. Jeśli zostanie zaimplementowane this issue, będziemy mieli bardziej niezawodną alternatywę.


Mogliśmy również zaczęli wektorem szerokości kolumn ww wykonując:

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) 

I moglibyśmy wybrali które kolumny aby wykluczyć bardziej wydajnie przy użyciu negatywne wskaźniki jak:

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

Następnie należy wymienić col_ends$beg[ii] na abs(col_ends$beg[ii]) iw kolejna linia:

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

Wreszcie, jeśli chcesz, aby nazwy kolumn należy czytać programowo jak dobrze, można oczyścić z 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 != ""] 

(zauważ, że łącząc ten krok z fread wymagałoby utworzenia kopii tabeli w celu usunięcia wiersza nagłówka, a zatem byłoby nieefektywne w przypadku dużych zestawów danych)