Прочитать текстовый файл с фиксированной шириной
Я пытаюсь загрузить этот уродливый формат данных в мой сеанс 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-кадр данных.
спасибо!
Ответы
Ответ 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
)
Ответ 4
Теперь вы можете использовать функцию read_fwf()
в пакете Hadley Wickham readr
.
Ожидается огромное улучшение производительности по сравнению с базой read.fwf()
.
Ответ 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.