実行環境
ファイルの例
作業としては、先日、更新時刻順でファイルリストを作った続きです。「数値がスペース区切りで入ってる」と聞いていたファイルを、とりあえずMery(エディタ)で開いたら「ファイルに含まれていたNULL文字は、スペースに変換して開きます」とのメッセージ。
実際の中身は載せられないので簡単なダミーで示すと ↓ こんな感じ。二つ目の画像はStirling(バイナリエディタ)で開いたところ。改行(LF、0x0A)の後、確かに0x00があります。ダミーファイルの実物はこちら。
※追記(9月20日)上の画像は最初にDOSで作成したもので、ファイル終端に余分な制御文字(EOF、0x1A)が入っており、その後作り直しました。メモ帳で開いた時に全然読めない ↓ のも、このためです。詳しくは翌日の記事を参照。
Rで、NULL文字をスキップして1行ずつベクトルに入れる
ファイル読み込みの関数・方法はいろいろですが、今回は(1)readLinesでNULL文字をスキップして1行ずつペクトルに入れる(2)各行を空白で分割して列に変換、という手順でmatrixにしました。(2)でstrsplit関数の結果を数値に変換してmatrixにする所が少し面倒。もっと簡単な方法があるかもしれません。sapply関数でつなげると何故か列方向になったので、とりあえず転置しました。
rows = readLines('R:/TMP/all.prn', skipNul=T)
print(rows)
[1] "1 1 1 1 1 1 1 1 1 1"
[2] "2 2 2 2 2 2 2 2 2 2"
[3] "3 3 3 3 3 3 3 3 3 3"
[4] "4 4 4 4 4 4 4 4 4 4"
[5] "5 5 5 5 5 5 5 5 5 5"
[6] "6 6 6 6 6 6 6 6 6 6"
[7] "7 7 7 7 7 7 7 7 7 7"
[8] "8 8 8 8 8 8 8 8 8 8"
[9] "9 9 9 9 9 9 9 9 9 9"
mat = t(sapply(strsplit(rows, ' '), as.numeric))
print(mat)
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,] 1 1 1 1 1 1 1 1 1 1
[2,] 2 2 2 2 2 2 2 2 2 2
[3,] 3 3 3 3 3 3 3 3 3 3
[4,] 4 4 4 4 4 4 4 4 4 4
[5,] 5 5 5 5 5 5 5 5 5 5
[6,] 6 6 6 6 6 6 6 6 6 6
[7,] 7 7 7 7 7 7 7 7 7 7
[8,] 8 8 8 8 8 8 8 8 8 8
[9,] 9 9 9 9 9 9 9 9 9 9
以下は(2)での少し違う書き方。sapplyでなくlapply関数を使うと ↓ こんな感じ。いずれにしてもstrsplitがlistを返すので、自分の知ってる範囲だと妙にややこしい手順しかできません。
do.call(rbind, lapply(strsplit(rows, ' '), as.numeric))
まず文字型のままmatrixにし、後から数値に直す方が ↓ 2行になるけど分かりやすいかも。
mat = do.call(rbind, strsplit(rows, ' '))
apply(mat, 2, as.numeric)
普通のプログラミング言語のようにFORループなら ↓ こんな感じ。数値以外のデータがあるとas.numericが失敗して止まるので、問題箇所の把握には有利。
lis = strsplit(rows, ' ')
mat = NULL
for (i in 1:length(lis)) {
mat = rbind(mat, as.numeric(lis[[i]]))
}
print(mat)
ファイル読み込みで失敗した例
NULL文字を考慮せず普段のようにやってみて失敗した例を、後々のため載せておきます。まずreadLines関数でオプションskipNul=TRUEがないと ↓ こんな風に2行目以降が取得できません。
readLines('R:/TMP/all.prn')
[1] "1 1 1 1 1 1 1 1 1 1" "" ""
[4] "" "" ""
[7] "" "" ""
[10] ""
Warning messages:
1: In readLines("R:/TMP/all.prn") :
line 2 appears to contain an embedded nul
2: In readLines("R:/TMP/all.prn") :
line 3 appears to contain an embedded nul
3: In readLines("R:/TMP/all.prn") :
line 4 appears to contain an embedded nul
4: In readLines("R:/TMP/all.prn") :
line 5 appears to contain an embedded nul
5: In readLines("R:/TMP/all.prn") :
line 6 appears to contain an embedded nul
6: In readLines("R:/TMP/all.prn") :
line 7 appears to contain an embedded nul
7: In readLines("R:/TMP/all.prn") :
line 8 appears to contain an embedded nul
8: In readLines("R:/TMP/all.prn") :
line 9 appears to contain an embedded nul
9: In readLines("R:/TMP/all.prn") :
line 10 appears to contain an embedded nul
10: In readLines("R:/TMP/all.prn") :
incomplete final line found on 'R:/TMP/all.prn'
read.table関数でデリミタを半角スペースに指定したら、なぜか2~5行目が飛ばされました。
read.table('R:/TMP/all.prn', sep=' ')
V1 V2 V3 V4 V5 V6 V7 V8 V9 V10
1 1 1 1 1 1 1 1 1 1 1
2 NA 6 6 6 6 6 6 6 6 6
3 NA 7 7 7 7 7 7 7 7 7
4 NA 8 8 8 8 8 8 8 8 8
5 NA 9 9 9 9 9 9 9 9 9
Warning messages:
1: In read.table("R:/TMP/all.prn", sep = " ") :
line 2 appears to contain embedded nulls
2: In read.table("R:/TMP/all.prn", sep = " ") :
line 3 appears to contain embedded nulls
3: In read.table("R:/TMP/all.prn", sep = " ") :
line 4 appears to contain embedded nulls
4: In read.table("R:/TMP/all.prn", sep = " ") :
line 5 appears to contain embedded nulls
5: In scan(file = file, what = what, sep = sep, quote = quote, dec = dec, :
embedded nul(s) found in input
もしファイルにNULL文字がなければ、上の二つとも ↓ 正常に読めます。
ところで、今日の記事用にNULL文字入りファイルをRで作るのが少し面倒でした。ファイルの最後だけに入れるなら簡単な一方、各行末に入れるというのが意外にできず、結局DOSのcopyコマンドを使用。何の役にも立ちませんが、せっかくなので明日書きます。
※追記(9月20日)その後、Rだけでできました。詳細は翌日の記事を参照。