J'essaie de charger cet ensemble de données au format moche dans ma session 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
Jusqu'à présent, je peux lire les lignes avec
x = readLines(path)
Mais le fichier mélange "espace" avec "-" en tant que séparateurs, et je ne suis pas un expert en regex. J'apprécie toute aide pour transformer cela en un cadre de données R agréable et propre. Merci!
C'est un fichier de largeur fixe. Utilisez read.fwf()
pour le lire:
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
Mise à jour
Le paquetage readr
(publié en avril 2015) offre une alternative simple et rapide.
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)))
Comparaison de la vitesse: readr::read_fwf()
était environ 2x plus rapide que utils::read.fwf ()
.
Une autre façon de déterminer les largeurs ...
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 dans l'argument widths indique qu'il y a une colonne d'un caractère qui doit être ignorée, tandis que -5 dans l'argument widths indique qu'il y a une colonne de cinq caractères à ignorer, de même ...
ref: https://www.inkling.com/read/r-cookbook-paul-teetor-1st/chapter-4/recipe-4-6
Tout d'abord, cette question est directement issue du cours "Obtenez des données et nettoyez-le" de Coursera par Leeks. Bien qu'il y ait une autre partie de la question, la partie difficile est la lecture du fichier.
Cela dit, le cours est principalement destiné à l'apprentissage.
Je déteste la procédure de largeur fixe de R. C'est lent et pour un grand nombre de variables, il devient très vite pénible de nier certaines colonnes, etc.
Je pense qu'il est plus facile d'utiliser readLines()
, puis d'utiliser substr()
pour créer vos variables.
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
)
Vous pouvez maintenant utiliser la fonction read_fwf()
dans le package readr
de Hadley Wickham.
Une amélioration considérable des performances est à prévoir par rapport à la base read.fwf()
.
Je documente ici la liste des alternatives pour la lecture de fichiers à largeur fixe en R, ainsi que des repères pour ce qui est le plus rapide.
Mon approche préférée est de combiner fread
avec stringi
; il est compétitif en tant qu'approche la plus rapide et présente l'avantage supplémentaire de stocker vos données sous forme de 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 = 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
Notez que fread
supprime automatiquement les espaces de début et de fin - parfois, cela n’est pas souhaitable, auquel cas définissez strip.white = FALSE
.
Nous aurions aussi pu commencer avec un vecteur de largeur de colonne ww
en faisant:
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)
Et nous aurions pu choisir les colonnes à exclure de manière plus robuste en utilisant des indices négatifs tels que:
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))
Puis remplacez col_ends$beg[ii]
Par abs(col_ends$beg[ii])
et à la ligne suivante:
paste0("V", which(col_ends$beg < 0))
Enfin, si vous souhaitez que les noms de colonne soient également lus par programmation, vous pouvez nettoyer avec 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 != ""]
(notez que la combinaison de cette étape avec fread
nécessiterait la création d'une copie de la table afin de supprimer la ligne d'en-tête et serait donc inefficace pour les grands ensembles de données)
Je ne connais rien à R, mais je peux vous fournir un regex qui correspondra à de telles lignes:
\s[0-9]{2}[A-Z]{3}[0-9]{4}(\s{5}[0-9]+\.[0-9]+[ -][0-9]+\.[0-9]+){4}