Подтвердить что ты не робот

Прочитать текстовый файл с фиксированной шириной

Я пытаюсь загрузить этот уродливый формат данных в мой сеанс 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

До сих пор я мог читать строки с помощью

  x = readLines(path)

Но файл смешивает "пробел" с "-" как разделители, и я не эксперт по регулярному выражению. Я ценю любую помощь, превращая это в хороший и чистый R-кадр данных. спасибо!

4b9b3361

Ответ 1

Это файл с фиксированной шириной. Используйте read.fwf() для чтения:

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

Обновление

Пакет readr (выпущен в апреле 2015 г.) обеспечивает простую и быструю альтернативу.

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

Сравнение скорости: readr::read_fwf() было ~ 2x быстрее, чем utils::read.fwf ().

Ответ 2

Другой способ определения ширины...

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 в аргументе width указывает, что существует столбец с одним символом, который следует игнорировать, -5 в аргументе widths указывает, что существует столбец с пятью символами, который следует игнорировать, аналогично...

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

Ответ 3

Во-первых, этот вопрос напрямую связан с курсом "Получить данные и очистить его" от Leeks. Хотя есть и другая часть вопроса, жесткая часть - это чтение файла.

Тем не менее, курс в основном предназначен для обучения.

Я ненавижу процедуру R фиксированной ширины. Он медленный и для большого количества переменных, он очень быстро становится болью, чтобы отрицать некоторые столбцы и т.д.

Я думаю, что его проще использовать readLines, а затем из этого использовать substr, чтобы сделать ваши переменные

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
                     )

Ответ 5

Я ничего не знаю о R, но я могу предоставить вам регулярное выражение, которое будет соответствовать таким строкам:

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

Мне жаль, что так долго, я постараюсь его оптимизировать.

EDIT:
Ха, теперь он вписывается в одну строку.

Ответ 6

Я документирую здесь список альтернатив для чтения файлов фиксированной ширины в R, а также предоставление некоторых тестов, для которых самый быстрый.

Мой предпочтительный подход заключается в объединении fread с stringi; он является конкурентоспособным как самый быстрый подход и имеет дополнительное преимущество (IMO) для хранения ваших данных как 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

Обратите внимание, что fread автоматически разделяет ведущее и конечное пробелы - иногда это нежелательно, и в этом случае установите strip.white = FALSE.

Также обратите внимание, что я выбрал sep = "\n", чтобы предотвратить разделение внутри строки. Если эта проблема, у нас будет более надежная альтернатива.


Мы могли бы также начать с вектора ширины столбцов ww, выполнив:

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)

И мы могли бы выбрать, какие столбцы лучше исключить, используя отрицательные индексы, например:

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

Затем замените col_ends$beg[ii] на abs(col_ends$beg[ii]) и в следующей строке:

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

Наконец, если вы хотите, чтобы имена столбцов также читались программно, вы можете очистить с помощью 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 != ""]

(обратите внимание, что объединение этого шага с fread потребует создания копии таблицы для удаления строки заголовка и, таким образом, будет неэффективно для больших наборов данных)

Ответ 7

Легкий метод, если для не-программистов (которые хотят выйти за пределы R)

  • Откройте страницу в веб-браузере.
  • Скопируйте и вставьте строки данных в текстовый редактор. Опустить заголовки столбцов.
  • Используйте поиск и замену для изменения нескольких пространств с одним пространством (Замените пространство-пространство пробелом. Нажимайте, пока не будет двойного  пробелы остались. Занимает всего несколько секунд).
  • Используйте поиск и замену для замены тире (-) пробелом
  • ForOse search-and-replace, чтобы заменить пробел запятой.

Теперь у вас есть CSV файл, который также легко прочитать человеку; сохрани это. Загрузите его в Excel, R или что-то еще и продолжайте обработку.

Ответ 8

Самый прямой способ - использовать read.fwf, как указано выше.

Хорошо, если конечная цель - получить его в R, вы всегда можете прочитать его в Excel для начала, использовать функцию "text to cloumns", чтобы визуально вырезать столбцы, а затем сохранить окончательный файл как CSV. После этого прочитайте CSV в R.