web-dev-qa-db-ja.com

固定幅でビッグデータを読み取る

固定幅でフォーマットされたビッグデータを読み取るにはどうすればよいですか? this の質問を読み、いくつかのヒントを試しましたが、すべての回答は区切りデータ(.csvとして)に対するものであり、私の場合ではありません。データは558MBで、何行かわかりません。

私が使用しているもの:

dados <- read.fwf('TS_MATRICULA_RS.txt', width=c(5, 13, 14, 3, 3, 5, 4, 6, 6, 6, 1, 1, 1, 4, 3, 2, 9, 3, 2, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 4, 11, 9, 2, 3, 9, 3, 2, 9, 9, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1), stringsAsFactors=FALSE, comment.char='', 
    colClasses=c('integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'character', 'character', 'character',
    'integer', 'integer', 'character', 'integer', 'integer', 'character', 'integer', 'character', 'character', 'character', 'character', 'character', 'character',
    'character', 'character', 'character', 'character', 'character', 'character', 'character', 'character', 'character', 'character', 'character', 'character',
    'character', 'character', 'character', 'character', 'character', 'character', 'character', 'character', 'character', 'character', 'character', 'integer',
    'integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'character', 'integer', 'integer', 'character', 'character', 'character',
    'character', 'integer', 'character', 'character', 'character', 'character', 'character', 'character', 'character', 'character'), buffersize=180000)

ただし、データの読み取りには30分(およびカウント...)かかります。新しい提案はありますか?

21
Rcoster

データに関する十分な詳細がないと、具体的な答えを出すのは難しいですが、始めるためのいくつかのアイデアがあります。

まず、Unixシステムを使用している場合は、wcコマンドを使用してファイルに関する情報を取得できます。たとえば、wc -l TS_MATRICULA_RS.txtはファイルの行数を示し、wc -L TS_MATRICULA_RS.txtはファイルの最長行の長さを報告します。これは知っておくと便利かもしれません。同様に、headtailを使用すると、テキストファイルの最初と最後の10行を検査できます。

次に、いくつかの提案:各フィールドの幅を知っているように見えるので、2つのアプローチのいずれかをお勧めします。

オプション1:csvkit +大きなデータをすばやく読み取るためのお気に入りの方法

csvkitはCSVファイルを操作するためのPythonツールのセットです。ツールの1つは in2csv であり、他のプログラムで使用できる適切なCSVを作成するために、「スキーマ」ファイルと組み合わせた幅形式のファイル。

スキーマファイル自体は、(1)変数名、(2)開始位置、および(3)幅の3つの列を持つCSVファイルです。 (in2csvのマニュアルページからの)例は次のとおりです。

    column,start,length
    name,0,30 
    birthday,30,10 
    age,40,3

そのファイルを作成すると、次のようなものを使用できるようになります。

in2csv -f fixed -s path/to/schemafile.csv path/to/TS_MATRICULA_RS.txt > TS_MATRICULA_RS.csv

そこから、「data.table」からfreadを使用してデータを読み取るか、sqldfを使用することを検討することをお勧めします。

オプション2:sqldfを使用してsubstr

あなたのような大きなデータファイルでsqldfを使用すると、実際にはかなり速くなり、substrを使用して読み取りたいものを正確に指定できるという利点があります。

繰り返しますが、これは、上記のようなスキーマファイルが利用可能であることを前提としています。スキーマファイルを取得したら、次の操作を実行できます。

temp <- read.csv("mySchemaFile.csv")

## Construct your "substr" command
GetMe <- paste("select", 
               paste("substr(V1, ", temp$start, ", ",
                     temp$length, ") `", temp$column, "`", 
                     sep = "", collapse = ", "), 
               "from fixed", sep = " ")

## Load "sqldf"
library(sqldf)

## Connect to your file
fixed <- file("TS_MATRICULA_RS.txt")
myDF <- sqldf(GetMe, file.format = list(sep = "_"))

幅がわかっているので、スキーマファイルの生成をスキップできる場合があります。幅からすると、cumsumを使用するのはほんの少しの作業です。 read.fwfの最初の例に基づいた基本的な例を次に示します。

ff <- tempfile()
cat(file = ff, "123456", "987654", sep = "\n")
read.fwf(ff, widths = c(1, 2, 3))

widths <- c(1, 2, 3)
length <- cumsum(widths)
start <- length - widths + 1
column <- paste("V", seq_along(length), sep = "")

GetMe <- paste("select", 
               paste("substr(V1, ", start, ", ",
                     widths, ") `", column, "`", 
                     sep = "", collapse = ", "), 
               "from fixed", sep = " ")

library(sqldf)

## Connect to your file
fixed <- file(ff)
myDF <- sqldf(GetMe, file.format = list(sep = "_"))
myDF
unlink(ff)
11

LaF パッケージは、固定幅のファイルを非常に高速に読み取るのに非常に優れています。私は毎日それを使用して、30列の+/- 100Mioレコードのファイルをロードします(あなたが持っているほど多くの文字列ではありません-主に数値データといくつかの要因)。そして、それはかなり速いです。だからこれが私がすることです。

library(LaF)
library(ffbase)
my.data.laf <- laf_open_fwf('TS_MATRICULA_RS.txt', 
                  column_widths=c(5, 13, 14, 3, 3, 5, 4, 6, 6, 6, 1, 1, 1, 4, 3, 2, 9, 3, 2, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 4, 11, 9, 2, 3, 9, 3, 2, 9, 9, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1), stringsAsFactors=FALSE, comment.char='', 
                  column_types=c('integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'categorical', 'categorical', 'categorical',
                               'integer', 'integer', 'categorical', 'integer', 'integer', 'categorical', 'integer', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical',
                               'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical',
                               'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'integer',
                               'integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'categorical', 'integer', 'integer', 'categorical', 'categorical', 'categorical',
                               'categorical', 'integer', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical'))
my.data <- laf_to_ffdf(my.data.laf, nrows=1000000)
my.data.in.ram <- as.data.frame(my.data)

PS。 read.fwfの速度が遅いことに悩まされ、最初にデータを解析するために使用していたPL/SQL PostgreSQLコードを維持するのが面倒になったため、LaFパッケージを使い始めました。

10
user1600826

これは、2015年4月にリリースされたHadleyWickhamとRStudioチームによって作成された新しいパッケージreadrを使用した純粋なRソリューションです。詳細 ここ 。コードは次のように単純です。

library(readr)

my.data.frame <- read_fwf('TS_MATRICULA_RS.txt',
                      fwf_widths(c(5, 13, 14, 3, 3, 5, 4, 6, 6, 6, 1, 1, 1, 4, 3, 2, 9, 3, 2, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 4, 11, 9, 2, 3, 9, 3, 2, 9, 9, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1)),
                      progress = interactive())

read_fwf{readr}の利点

  • readrLaFに基づいていますが、驚くべきことに高速です。 Rで固定幅ファイルを読み取る高速メソッド であることが示されています。
  • 代替案よりも単純です。例えばcolumn_typesは入力の最初の30行から入力されるため、心配する必要はありません。
  • プログレスバーが付属しています;)
6
rafa.pereira