我正在尝试将这种丑陋格式的数据集加载到我的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数据框架的帮助。 谢谢!
答案 0 :(得分:170)
这是一个固定宽度的文件。使用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年4月发布)提供了一种简单快捷的替代方案。
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()
比utils::read.fwf ()
快〜2倍。
答案 1 :(得分:53)
确定宽度的另一种方法......
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
)
widths参数中的-1表示应该忽略一个单字符列,widths参数中的-5表示应该忽略一个五字符列,同样......
参考:https://www.inkling.com/read/r-cookbook-paul-teetor-1st/chapter-4/recipe-4-6
答案 2 :(得分:16)
首先,这个问题直接来自Leeks的Coursera“Get Data and Clean It”课程。虽然问题的另一部分,但困难的部分是阅读文件。
也就是说,该课程主要用于学习。
我讨厌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
)
答案 3 :(得分:10)
您现在可以在Hadley Wickham的read_fwf()
包中使用readr
函数。
与基础read.fwf()
相比,预计会有巨大的性能提升。
答案 4 :(得分:5)
我记录了here在R中读取固定宽度文件的备选方案列表,并提供了一些最快的基准测试。
我首选的方法是将fread
与stringi
合并;它作为最快的方法具有竞争力,并且具有将您的数据存储为data.table
的附加好处(IMO):
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
请注意fread
会自动删除前导和尾随空格 - 有时,这是不合需要的,在这种情况下设置为strip.white = FALSE
。
我们也可以通过以下方式开始使用列宽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
结合使用会需要创建表的副本以删除标题行,因此对于大型数据集来说效率很低)
答案 5 :(得分:4)
我不知道关于R的事情,但我可以为你提供一个匹配这些行的正则表达式:
\s[0-9]{2}[A-Z]{3}[0-9]{4}(\s{5}[0-9]+\.[0-9]+[ -][0-9]+\.[0-9]+){4}