固定幅のテキストファイルを読み取る


89

この醜いフォーマットのデータセットを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データフレームに変える上での助けに感謝します。ありがとう!


5
そして、read.fwf固定幅でフォーマットされたデータを読み取るために見てください。
Paul Hiemstra 2013年

1
各行を処理することをお勧めします。'-'と ''文字が混在しています。
フェルナンド

または、空白または-は1文字にすぎないので、最初にスペースの複数の出現をすべてタブ文字に置き換え、次にすべてのタブ区切りエントリの-または空白を分割します。
GitaarLAB 2013年

固定幅=セパレータなし。つまり、「-」はマイナス記号であり、スペースもセパレータではありません。数字が使用可能な幅全体を満たさない場合にのみ発生します
Eusebio Rufian-Zilbermann

回答:


181

これは固定幅ファイルです。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()最大2倍の速さutils::read.fwf ()でした。


8
@Andrieどのようにして幅とスキップが何であるかを知ったのですか?
コバ14

12
@コバ:行の1つをコピーして、列数のあるテキストエディターに貼り付け、各列の幅(必要に応じて空白を含む)を手動で数えました。また、生データに到達する前に4行全体をスキップする必要があることもわかります。
rayryeng 14

5
以下の@Pavithraの回答で、不要な空白をスキップするための負の列幅を使用すると、受け入れられた回答に適している可能性があります。
Marius Butuc、2014年

1
@Andrieどのようにしてfwf_widths値を取得しましたか?
BICube 2017

3
@アラ私はreadr::fwf_emptyあなたのために幅を推測しようとすると信じています。の例readr::read_fwfは、の使用法を示していますreadr::fwf_empty
ジェイクフィッシャー

55

幅を決定する別の方法...

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は、無視する必要がある1文字の列があることを示し、widths引数の-5は、無視する必要がある5文字の列があることを示しています...

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


20

まず、その質問は、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
                     )

2
このアプローチは私にとってうまくいきました。2つの追加のヒント:1)mydataを必要なデータだけに定義できます。したがってmydata <- data.frame(var4 = substr(x,29,32))、データの4番目の列のみが必要であるかのように、それは単純である可能性があります。また、Windowsユーザーの場合、TextFXプラグインを備えたNotepad ++を使用すると、プレーンでシンプルなカウントされた文字定規が得られるため、開始値と終了値に何を配置するかを理解できますsubstr。ただし、ストップ値は、保持する最後の文字の位置より1つ多いことに注意してください。
globalSchmidt 2017年


5

ここに文書化します 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 = 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先頭と末尾の空白を自動的に取り除くことに注意してください。これは望ましくない場合があり、その場合はsetになり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、ヘッダー行を削除するためにテーブルのコピーを作成する必要があるため、大きなデータセットの場合は効率が悪いことに注意してください)


4

Rについては知りませんが、次のような行に一致する正規表現を提供できます。

\s[0-9]{2}[A-Z]{3}[0-9]{4}(\s{5}[0-9]+\.[0-9]+[ -][0-9]+\.[0-9]+){4}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.