R入門
ファイル・ディレクトリ
最終更新:
r-intro
目次
ファイル
読み込み
テキストファイルの中身を簡単に読み込む
scan関数を使うとテキストファイルの中身をベクトルに簡単に読み込むことができる。以下の6行からなるテキストファイルを「text.txt」として保存する。
A
abc
あいう
阿伊宇
123xyz
読み込んでみる。
> lines <- scan("text.txt", what = character(0))
Read 5 items
> print(lines)
[1] "A" "abc" "あいう" "阿伊宇" "123xyz"
whatオプションをcharacter(0)とすることで、すべてを文字列で読み込む。デフォルトでは一行一要素でベクトルに代入される。空行(5行目)はデフォルトでは読み込まれない。これを読み込むようにするには、blank.lines.skipオプションをFALSEにする。
> lines <- scan("text.txt", what = character(0), blank.lines.skip = FALSE)
Read 6 items
> print(lines)
[1] "A" "abc" "あいう" "阿伊宇" "" "123xyz"
「Read 6 items」を表示しなくするには、quietオプションをTRUEにする。
> lines <- scan("text.txt", what = character(0), quiet = TRUE)
> print(lines)
[1] "A" "abc" "あいう" "阿伊宇" "123xyz"
ヌル(0x00)を含むCSVファイルやTSVファイルを読み込む
始めにヌルを含むCSVファイルを作成する。
> ch1 <- c(0x41:0x43, 0x2c, 0x00, 0x2c, 0x47:0x49, 0x0d, 0x0a)
> ch1 <- c(0x41:0x43, 0x2c, 0x00, 0x2c, 0x47:0x49, 0x0d, 0x0a)
> ch2 <- c(0x61, 0x00, 0x63, 0x2c, 0x64:0x66, 0x2c, 0x67:0x69, 0x0d, 0x0a)
> ra <- as.raw(c(ch1, ch2))
> writeBin(ra, "temp.csv")
ファイルをメモ帳で開くと、以下のようになる。1行目の2列目は列の値自体がヌルで、2行目の1列目は「a」と「c」の間は空白(0x20)ではなくヌル(0x00)である。
ABC, ,GHI
a c,def,ghi
標準で搭載されているread.tableは、skipNulオプションにTRUEを指定しないと、ヌルだけの列は列とは認識されず、行によって列数が異なることになるため、エラーが発生して読み込みに失敗する。skipNulオプションにTRUEを指定と、ヌルは完全に無視して他はすべて読み込まれる。ヌルの次の「c」もきちんと読み込まれている。
> dtf <- read.table("temp.csv", header = FALSE, sep = ",")
scan(file = file, what = what, sep = sep, quote = quote, dec = dec, でエラー:
line 2 did not have 2 elements
追加情報: 警告メッセージ:
1: read.table("temp.csv", header = FALSE, sep = ",") で:
line 1 appears to contain embedded nulls
2: read.table("temp.csv", header = FALSE, sep = ",") で:
line 2 appears to contain embedded nulls
> print(dtf)
エラー: オブジェクト 'dtf' がありません
> dtf <- read.table("temp.csv", header = FALSE, sep = ",", skipNul = TRUE)
> print(dtf)
V1 V2 V3
1 ABC GHI
2 ac def ghi
readrパッケージのread_delim関数を試してみる。ヌルだけの列はきちんと処理されているようだが、ヌルを含む列は、ヌル以降は読み込まれていない(「c」が表示されない)。
> library(readr)
> tib <- read_delim("temp.csv", delim = ",", col_names = FALSE, progress = FALSE, show_col_types = FALSE)
警告メッセージ:
One or more parsing issues, call `problems()` on your data frame for details, e.g.:
dat <- vroom(...)
problems(dat)
> print(data.frame(tib))
X1 X2 X3
1 ABC <NA> GHI
2 a def ghi
data.tableパッケージのfread関数を使う。これはヌルを完全に無視して読み込むし、ヌルだけの列は空欄(NA)ということで処理できているし、ヌル以降の文字もきちんと読み込まれている。
> library(data.table)
> dtt <- fread("temp.csv", header = FALSE, sep = ",", showProgress = FALSE)
> print(dtt)
V1 V2 V3
1: ABC GHI
2: ac def ghi
ヌル(NULL)が含まれるテキストファイルをread.table関数で読み込む
read.table関数は、読み込むファイルにヌル(NULL、0x00)が含まれていると、列内のヌル以降は読み込まなくなる。これをヌルは無視してとにかく読み込むようにするには、skipNulオプションにTRUEを指定する。以下は、3行からなるテキストファイルtemp.txtを作成し、そのファイルを読み込んだ例。3行目の「c」の次にはヌルを含んでおり、デフォルトでは警告が発生しているが、skipNulオプションにTRUEを指定すると、ヌルを無視してすべて読み込んでいることがわかる。
> Sys.getlocale()
[1] "LC_COLLATE=Japanese_Japan.utf8;LC_CTYPE=Japanese_Japan.utf8;LC_MONETARY=Japanese_Japan.utf8;LC_NUMERIC=C;LC_TIME=Japanese_Japan.utf8"
> ch1 <- c(0x30:0x39, 0x0d, 0x0a, 0x41:0x5a, 0x0d, 0x0a)
> ch2 <- c(0x61:0x63, 0x00, 0x65:0x7a, 0x0d, 0x0a)
> ra <- as.raw(c(ch1, ch2))
> writeBin(ra, "temp.txt")
> read.table("temp.txt")
V1
1 0123456789
2 ABCDEFGHIJKLMNOPQRSTUVWXYZ
3 abc
警告メッセージ:
read.table("temp.txt") で: line 3 appears to contain embedded nulls
> read.table("temp.txt", skipNul = TRUE)
V1
1 0123456789
2 ABCDEFGHIJKLMNOPQRSTUVWXYZ
3 abcefghijklmnopqrstuvwxyz
ヌル(0x00)を含むテキストファイルを高速に読み込む
始めにヌルを含む巨大なテキストファイルを作成する。以下は文字コードがUTF-8の環境のため(3×5+2)×2×10^7=340,000,000バイト(約324MB)のテキストファイルを作成している。ファイルの行数は10^7=10,000,000行。それぞれの行は苗字と名前の間にヌル(0x00)が挟まれている。
> Sys.getlocale()
[1] "LC_COLLATE=Japanese_Japan.utf8;LC_CTYPE=Japanese_Japan.utf8;LC_MONETARY=Japanese_Japan.utf8;LC_NUMERIC=C;LC_TIME=Japanese_Japan.utf8"
> ra1 <- unlist(iconv("石見", toRaw = TRUE))
> ra2 <- unlist(iconv("舞菜香", toRaw = TRUE))
> ra3 <- unlist(iconv("和多田", toRaw = TRUE))
> ra4 <- unlist(iconv("美咲", toRaw = TRUE))
> ra <- c(ra1, as.raw(0), ra2, as.raw(0x0a), ra3, as.raw(0), ra4, as.raw(0x0a))
> writeBin(rep(ra, 10 ^ 7), "temp.txt")
> file.info(dir(patter = "temp\\.txt"))["size"]
size
temp.txt 3.4e+08
scan関数を使用して読み込む場合は、skipNulオプションにTRUEを指定しないとうまく読み込むことができない。
> lns <- scan("temp.txt", what = character(), sep = "\n", quiet = TRUE)
警告メッセージ:
scan("temp.txt", what = character(), sep = "\n", quiet = TRUE) で:
入力文字列の中に nul が埋め込まれています
> length(lns)
[1] 20000000
> lns[1:3]
[1] "石見" "和多田" "石見"
> lns <- scan("temp.txt", what = character(), sep = "\n", quiet = TRUE, skipNul = TRUE)
> length(lns)
[1] 20000000
> lns[1:3]
[1] "石見舞菜香" "和多田美咲" "石見舞菜香"
read.table関数を使用して読み込む場合も、skipNulオプションにTRUEを指定しないとうまく読み込むことができない。
> dtf <- read.table("temp.txt", header = FALSE, sep = "\n")
警告メッセージ:
1: read.table("temp.txt", header = FALSE, sep = "\n") で:
line 1 appears to contain embedded nulls
2: read.table("temp.txt", header = FALSE, sep = "\n") で:
line 2 appears to contain embedded nulls
(表示省略)
入力文字列の中に nul が埋め込まれています
> nrow(dtf)
[1] 20000000
> head(dtf, 3)
V1
1 石見
2 和多田
3 石見
> dtf <- read.table("temp.txt", header = FALSE, sep = "\n", skipNul = TRUE)
> nrow(dtf)
[1] 20000000
> head(dtf, 3)
V1
1 石見舞菜香
2 和多田美咲
3 石見舞菜香
それぞれの関数で読み込みに要する時間を計測してみる。
> system.time(
+ scan("temp.txt", what = character(), sep = "\n", quiet = TRUE, skipNul = TRUE)
+ )
ユーザ システム 経過
3.06 0.14 3.86
> system.time(
+ scan("temp.txt", what = character(), sep = "\n", quiet = TRUE, skipNul = TRUE)
+ )
ユーザ システム 経過
3.35 0.14 3.89
> system.time(
+ read.table("temp.txt", header = FALSE, sep = "\n", skipNul = TRUE)
+ )
ユーザ システム 経過
3.06 0.09 4.03
> system.time(
+ read.table("temp.txt", header = FALSE, sep = "\n", skipNul = TRUE)
+ )
ユーザ システム 経過
2.92 0.20 4.06
scan関数の方が若干早い。なお、単純にテキストファイルを読み込むだけであればreadrパッケージのfread関数やread_lines関数のほうが高速に動作するが、以下の例のとおりにヌルを含むとうまく動作をしない。これを制御するオプションは無いようだ。
> library(readr)
> fread("temp.txt", sep = "\n")
fread("temp.txt", sep = "\n") でエラー:
文字列の中に nul が埋め込まれています: '石見\0舞菜香'
追加情報: 警告メッセージ:
fread("temp.txt", sep = "\n") で:
Previous fread() session was not cleaned up properly. Cleaned up ok at the beginning of this fread() call.
> read_lines("temp.txt", progress = FALSE)
character(0)
書き込み
ベクトルの要素をテキストファイルに書き込む
write関数を使う。次のベクトルの中身をテキストファイル「output.txt」に書き込む
> s <- c("a", "AB", "あいう", "", "阿伊宇")
> write(s, file = "output.txt")
カレントディレクトリにファイル「output.txt」がつくられ、一要素一行の以下のような中身になっているはず。同名ファイルが既にある場合は、そのファイルはいったん削除され、新たにファイルがつくられる。
a
AB
あいう
阿伊宇
既にある同名ファイルに追加したい場合は、appendオプションをTRUEにする。
> write(s, file = "output.txt", append = TRUE)
ファイルoutput.txtの中身は以下のようなったはず。
a
AB
あいう
阿伊宇
a
AB
あいう
阿伊宇
これまでは文字列型ベクトルを出力していたが、数値型ベクトルの場合は次のように書き込まれる。
> n <- 1:3
> write(n, file = "output.txt")
1 2 3
要素と要素の間のセパレーターはデフォルトでは空白一つ(0x20)。これを変えるにはsepオプションにセパレーターを指定する。
> write(n, file = "output.txt", sep = "\n")
1
2
3
ファイルへの高速な書き込み
data.tableパッケージのfwrite関数を使う。以下は、行数が100万のデータフレームを、write.table関数とfwrite関数を使ってそれぞれTSV形式のテキストファイルに書き込んだ例。書き込んだ行数はヘッダー行も含むため100万1行であることに注意。それぞれ2回繰り返し行ったが、fwrite関数による書き込みのほうが10倍以上速いことがわかる。
> library(data.table)
> n <- 10 ^ 6
> no <- 1:n
> s <- c("カナメ", "フレイア", "美雲", "マキナ", "レイナ")
> name <- sample(s, n, replace = TRUE)
> shoe_size <- round(rnorm(n, 23.5, 1), 1)
> dtf <- data.frame(no, name, shoe_size)
> head(dtf, 3)
no name shoe_size
1 1 美雲 22.6
2 2 マキナ 22.5
3 3 レイナ 23.5
> system.time(
+ write.table(dtf, "temp.tsv", sep = "\t", row.name = FALSE, quote = FALSE)
+ )
ユーザ システム 経過
3.48 0.18 3.71
> system.time(
+ write.table(dtf, "temp.tsv", sep = "\t", row.name = FALSE, quote = FALSE)
+ )
ユーザ システム 経過
3.45 0.09 3.54
> system.time(
+ fwrite(dtf, "temp.tsv", sep = "\t", row.name = FALSE, quote = FALSE)
+ )
ユーザ システム 経過
0.07 0.02 0.04
> system.time(
+ fwrite(dtf, "temp.tsv", sep = "\t", row.name = FALSE, quote = FALSE)
+ )
ユーザ システム 経過
0.16 0.00 0.05
fwriteによる日付時刻型の出力
data.tableパッケージのfwrite関数では、日付時刻型のオブジェクトを出力するとUTCに変換して出力されてしまう(ちょうど9時間前の日付時刻が出力される)。以下の例のとおり、出力元のオブジェクトのタイムゾーンをJSTに設定しても、出力はUTCの日付時刻になり、それを表す記号(Z)が付けられて出力される。オブジェクトの値をそのまま(JSTのまま)出力したい場合は、dateTimeAsオプション(デフォルトは「ISO」)に「write.csv」を指定すると、よく見る書式でかつJSTで出力される。
「write.csv」を指定したときのファイルはExcelで開くと、その列はそのまま日付時刻型の値になる便利な書式である。
> library(data.table)
> library(lubridate)
> n <- 3
> no <- 1:n
> dtm <- make_datetime(2000, 1:n, 1, 2, 3, 4, "Asia/Tokyo")
> dtf <- data.frame(no, name, dtm)
> print(dtf)
no name dtm
1 1 January 2000-01-01 02:03:04
2 2 February 2000-02-01 02:03:04
3 3 March 2000-03-01 02:03:04
> fwrite(dtf, "temp.csv", sep = ",")
> shell("type temp.csv")
no,name,dtm
1,January,1999-12-31T17:03:04Z
2,February,2000-01-31T17:03:04Z
3,March,2000-02-29T17:03:04Z
> fwrite(dtf, "temp.csv", sep = ",", dateTimeAs = "ISO")
> shell("type temp.csv")
no,name,dtm
1,January,1999-12-31T17:03:04Z
2,February,2000-01-31T17:03:04Z
3,March,2000-02-29T17:03:04Z
> fwrite(dtf, "temp.csv", sep = ",", dateTimeAs = "squash")
> shell("type temp.csv")
no,name,dtm
1,January,19991231170304000
2,February,20000131170304000
3,March,20000229170304000
> fwrite(dtf, "temp.csv", sep = ",", dateTimeAs = "write.csv")
> shell("type temp.csv")
no,name,dtm
1,January,2000-01-01 02:03:04
2,February,2000-02-01 02:03:04
3,March,2000-03-01 02:03:04
テンポラリファイルを利用する
一時的なファイル(テンポラリファイル)を利用するにはtempfile関数を使う。tempfile関数はテンポラリファイルを作成するのではなく、テンポラリファイルとして使用できるファイル名を返すことに注意。以下、実行例。
> filename <- tempfile()
> filename
[1] "C:\\Users\\○○\\AppData\\Local\\Temp\\××\\□□"
> write(1:3, file = filename)
> dtf <- read.table(file = filename)
> dtf
V1 V2 V3
1 1 2 3
上記はWindows 10 で実行した例。○○はアカウント名、××と□□は任意の文字列。××は現在起動したR専用のテンポラリディレクトリであり、そのRを終了するとこのディレクトリは自動で削除される。□□はテンポラリファイルのファイル名で、このファイルも自動で削除される。
このテンポラリディレクトリ名を得るにはtempdir関数を使う。
> tempdir()
[1] "C:\\Users\\○○\\AppData\\Local\\Temp\\××"
文字コードを指定してCSVファイルを読み込む
read.csv関数を使う。その際、fileEncodingオプションに文字コードを指定する。シフトJIS(CP932)であれば「CP932」を、UTF-8であれば「UTF-8」を指定する。特に指定をしないと、今の環境のロケールの文字コードで読み込む。指定に誤りがあると、エラーが発生する。
以下は、以下のテキストをそれぞれシフトJIS(CP932)でtextcp932.csv、UTF-8でtextutf8.csvと保存をして、それぞれ読み込ませた例。
no,姓,名
1,中野,一花
2,中野,二乃
> Sys.getlocale()
[1] "LC_COLLATE=Japanese_Japan.932;LC_CTYPE=Japanese_Japan.932;LC_MONETARY=Japanese_Japan.932;LC_NUMERIC=C;LC_TIME=Japanese_Japan.932"
> dtf <- read.csv("textcp932.csv")
> print(dtf)
no 姓 名
1 1 中野 一花
2 2 中野 二乃
> dtf <- read.csv("textcp932.csv", fileEncoding = "CP932")
> print(dtf)
no 姓 名
1 1 中野 一花
2 2 中野 二乃
> dtf <- read.csv("textutf8.csv")
make.names(col.names, unique = TRUE) でエラー:
2 は不正なマルチバイト文字です
> dtf <- read.csv("textcp932.csv", fileEncoding = "CP932")
> print(dtf)
no 姓 名
1 1 中野 一花
2 2 中野 二乃
BOM(バイトオーダーマーク)が付いたファイルを読み込む
fileEncodingオプションを使う。BOMが付いたUTF-8の場合はUTF-8-BOM、UTF-16の場合はUTF-16を指定するが、そのまま読み込んでくれる。以下は、read.csv関数を使用した例。
以下の3行を、それぞれBOM付きのUTF-8、UTF-16形式で、bomutf8.csv、bomutf16.csvで保存する。
no,姓,名
1,佐藤,太郎
2,鈴木,次郎
read.csv関数で読み込む。
> dtf <- read.csv("bomutf8.csv")
make.names(col.names, unique = TRUE) でエラー:
'<ef>サ<bf>no' に不正なマルチバイト文字があります
> dtf <- read.csv("bomutf8.csv", fileEncoding = "UTF-8-BOM")
> dtf
no 姓 名
1 1 佐藤 太郎
2 2 鈴木 次郎
> dtf <- read.csv("bomutf16.csv", fileEncoding = "UTF-16")
> dtf
no 姓 名
1 1 佐藤 太郎
2 2 鈴木 次郎
BOMについてはこちらを参照のこと。RにおけるBOMの扱いは、connectionsのヘルプを参照。
> ?connections
新常用漢字表の漢字を含むテキストファイルを読み込む
Windows版Rのバージョン4.1.3までは、新常用漢字表の漢字のうちUnicodeにしか存在しない文字、すなわちシフトJISコードが割り当てられていない漢字を含むテキストファイルを読み込むことはエンコードを指定してもできなかった。例えば、以下の内容をテキストファイルmoji.txtとしてUTF-8で保存する。
ABC123
鈴木みのり
セナディア
補塡する
頰をなでる
辰𠮷𠀋一郎
𩸽(ホッケ)を食べる
𩹉(トビウオ)を捕まえる
バージョン4.1.3で文字コードにUTF-8を指定してscan関数で読み込むと失敗する。
> R.Version()$version.string
[1] "R version 4.1.3 (2022-03-10)"
> s <- scan(file = "moji.txt", what = character(), sep = "\n", fileEncoding = "UTF-8")
Read 4 items
警告メッセージ:
scan(file = "moji.txt", what = character(), sep = "\n", で:
入力コネクション 'moji.txt' に不正な入力がありました
> print(s)
[1] "ABC123" "鈴木みのり" "セナディア" "補"
バージョン4.2.2で文字コードにUTF-8を指定してscan関数で読み込むとうまくいく。
> R.Version()$version.string
[1] "R version 4.2.0 (2022-04-22 ucrt)"
> s <- scan(file = "moji.txt", what = character(), sep = "\n", fileEncoding = "UTF-8")
Read 8 items
> print(s)
[1] "ABC123" "鈴木みのり" "セナディア"
[4] "補塡する" "頰をなでる" "辰𠮷𠀋一郎"
[7] "𩸽(ホッケ)を食べる" "𩹉(トビウオ)を捕まえる"
サロゲートペアの文字(6~8要素目)も、正しく読み込んでいることがわかる。
警告メッセージ「line ○ appears to contain embedded nulls」
read.tableやread.csv関数を使用してこのメッセージが表示されたときは、読み込んだファイルにヌル(0x00、NULL)が含まれており、そのために正しく読み込めていない可能性が高い。skipNulオプションをTRUEにすると、ヌルをスキップして読み込むようになり、このメッセージが表示されなくなる。
> dtf <- read.csv("○○○", header = TRUE)
警告メッセージ:
read.table(file = file, header = header, sep = sep, quote = quote, で:
line ○ appears to contain embedded nulls
> dtf <- read.csv("○○○", header = TRUE, skipNul = TRUE)
>
サイズが非常に大きなテキストファイルを簡単に作成する
動作確認でサイズが非常に大きなテキストファイルが必要なときがあるが、文字型ベクトルを使うと簡単に作成することができる。
以下は、Windows環境でサイズが5億バイト(≒476.8MB)のファイルを、一つのコマンドで作成している。10バイトの文字列("AB12あい"の8バイトと改行コードCR+LFの2バイト)を5,000万個作り、それをテキストファイルに出力している。文字コードはシフトJIS、改行コードはCR+LFとしているため、サイズが単純に10バイト×5,000万=5億バイトとなっている。作成には10分弱要している。
> cat(rep("AB12あい", 5 * 10 ^ 7), file = "temp.txt", sep = "\n")
> dir(".", "temp\\.txt")
[1] "temp.txt"
> file.size("temp.txt")
[1] 5e+08
様々な文字コードのCSVファイルを読み込む
read.table関数を使う。fileEncodingオプションに文字コードを指定する。
動作確認のため、最初にPowerShellを使ってカレントディレクトリに、順番にシフトJIS、UTF-8(BOM無し)、UTF-8(BOM付き)、UTF-16(ビッグエンディアン、BOM付き)、UTF-16(リトルエンディアン、BOM付き)のCSVファイルを出力する。PowerShellのコマンドレットでは、Unicode系は原則BOM付きとなる。そのため、BOM無しのUTF-8の出力には、FileクラスのWriteAllLinesメソッドを使用している。
PS > $lines = "1,ABC", "2,abc", "3,あいう"
PS > $odir = (gl).Path
PS > $lines | Out-File -Encoding default ($odir + "\sjis.csv")
PS > [IO.File]::WriteAllLines(($odir + "\utf8nb.csv"), $lines)
PS > $lines | Out-File -Encoding utf8 ($odir + "\utf8wb.csv")
PS > $lines | Out-File -Encoding bigendianunicode ($odir + "\utf16bewb.csv")
PS > $lines | Out-File -Encoding unicode ($odir + "\utf16lewb.csv")
PS > Get-Content .\sjis.csv
1,ABC
2,abc
3,あいう
PS > Get-Content .\utf8nb.csv -Encoding utf8
1,ABC
2,abc
3,あいう
Rを起動して、read.table関数で読み込んでみる。現在の環境下における文字コードは特にオプションを指定しなくても読み込むことができる。
> Sys.getlocale()
[1] "LC_COLLATE=Japanese_Japan.utf8;LC_CTYPE=Japanese_Japan.utf8;LC_MONETARY=Japanese_Japan.utf8;LC_NUMERIC=C;LC_TIME=Japanese_Japan.utf8"
> read.table("sjis.csv", sep = ",")
V1 V2
1 no name
2 1 ABC
3 2 abc
4 3 \x82\xa0\x82\xa2\x82\xa4
> read.table("utf8nb.csv", sep = ",")
V1 V2
1 no name
2 1 ABC
3 2 abc
4 3 あいう
fileEncodingオプションにそれぞれ文字コードを指定する。UTF-16の場合、「UTF-16」を指定すればバイトオーダーマークからエンディアンを推定して読み込む。エンディアンを指定することもできる。最後の例のとおりに、エンディアンの指定を間違えると、指定のとおりに読み込もうとして読み込みに失敗する。
> read.table("sjis.csv", sep = ",", fileEncoding = "SJIS")
V1 V2
1 1 ABC
2 2 abc
3 3 あいう
> read.table("utf8nb.csv", sep = ",", fileEncoding = "UTF-8")
V1 V2
1 1 ABC
2 2 abc
3 3 あいう
> read.table("utf8wb.csv", sep = ",", fileEncoding = "UTF-8")
V1 V2
1 1 ABC
2 2 abc
3 3 あいう
> read.table("utf16bewb.csv", sep = ",", fileEncoding = "UTF16")
V1 V2
1 1 ABC
2 2 abc
3 3 あいう
> read.table("utf16lewb.csv", sep = ",", fileEncoding = "UTF16")
V1 V2
1 1 ABC
2 2 abc
3 3 あいう
> read.table("utf16bewb.csv", sep = ",", fileEncoding = "UTF-16BE")
V1 V2
1 1 ABC
2 2 abc
3 3 あいう
> read.table("utf16lewb.csv", sep = ",", fileEncoding = "UTF-16LE")
V1 V2
1 1 ABC
2 2 abc
3 3 あいう
> read.table("utf16lewb.csv", sep = ",", fileEncoding = "UTF-16BE")
V1
1 \ufffe\u3100Ⰰ䄀䈀䌀ഀ\u0a00㈀Ⰰ愀戀挀ഀ\u0a00㌀Ⰰ䈰䐰䘰ഀ\u0a00
警告メッセージ:
read.table("utf16lewb.csv", sep = ",", fileEncoding = "UTF-16BE") で:
incomplete final line found by readTableHeader on 'utf16lewb.csv'
テキストファイルを高速に読み込む
data.tableパッケージを利用する。以下は、100万行のテキストファイルtemp.txtを作成し、Rに標準で搭載されているread.table関数と、data.tableパッケージに含まれているfread関数で、それぞれそのファイルを読み込む時間を計測した結果。
> library(data.table)
> mx <- matrix(rnorm(1000000 * 4), ncol = 4)
> write.table(mx, "temp.txt", col.names = FALSE, row.names = FALSE)
> system.time(dtf <- read.table("temp.txt", header = FALSE))
ユーザ システム 経過
7.94 0.15 8.14
> system.time(dtb <- fread("temp.txt"))
ユーザ システム 経過
0.13 0.01 0.07
> system.time(dtf <- read.table("temp.txt", header = FALSE))
ユーザ システム 経過
7.41 0.09 7.51
> system.time(dtb <- fread("temp.txt"))
ユーザ システム 経過
0.17 0.02 0.04
> dim(dtf)
[1] 1000000 4
> dim(dtb)
[1] 1000000 4
> head(dtf)
V1 V2 V3 V4
1 1.7752384 -1.4123053 0.24326013 0.5067002
2 -1.3369478 0.4076904 0.42491207 -1.6561556
3 -1.4287960 0.2838613 2.01597774 -1.0682637
4 0.7791319 0.5361162 0.05211674 0.2194605
5 -0.8555709 -0.5486108 0.11662963 2.0608156
6 0.8034380 -2.0021208 -0.29818598 -0.4815675
> dim(dtb)
[1] 1000000 4
> head(dtb)
V1 V2 V3 V4
1: 1.7752384 -1.4123053 0.24326013 0.5067002
2: -1.3369478 0.4076904 0.42491207 -1.6561556
3: -1.4287960 0.2838613 2.01597774 -1.0682637
4: 0.7791319 0.5361162 0.05211674 0.2194605
5: -0.8555709 -0.5486108 0.11662963 2.0608156
6: 0.8034380 -2.0021208 -0.29818598 -0.4815675
キャッシュの効果を考慮して、交互に2回ずつ実施している。最後に、読み込んだデータフレームとデータテーブルの次元とそれぞれの長さを表示している。ファイルの読み込みは、fread関数のほうが明らかに早いことがわかる。
バイナリファイルを作成する
数値型ベクトルでバイト列を作成し、それをロウ型に変換してwriteBin関数で出力すればよい。以下は、ch1とch2の2つの数値型ベクトルでバイト列を作成し、それを純粋にバイト単位でファイル出力した例。
> ch1 <- c(0x30:0x39, 0x0d, 0x0a, 0x41:0x5a, 0x0d, 0x0a, 0x61:0x7a, 0x0d, 0x0a)
> ch2 <- c(0xe3, 0x81, 0x82, 0xe3, 0x81, 0x84, 0xe3, 0x81, 0x86, 0x0d, 0x0a)
> ra <- as.raw(c(ch1, ch2))
> writeBin(ra, "temp.txt")
temp.txtを画面にダンプした結果は以下のとおり。
PS > Format-Hex .\temp.txt
パス: ○○○
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
00000000 30 31 32 33 34 35 36 37 38 39 0D 0A 41 42 43 44 0123456789..ABCD
00000010 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51 52 53 54 EFGHIJKLMNOPQRST
00000020 55 56 57 58 59 5A 0D 0A 61 62 63 64 65 66 67 68 UVWXYZ..abcdefgh
00000030 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 ijklmnopqrstuvwx
00000040 79 7A 0D 0A E3 81 82 E3 81 84 E3 81 86 0D 0A yz..ããã..
temp.txtをテキストエディタで文字コードをUTF-8に指定して開くと、以下のようになるはず。
0123456789
ABCDEFGHIJKLMNOPQRSTUVWXYZ
abcdefghijklmnopqrstuvwxyz
あいう
本例では、結果をわかりやすくするためUTF-8の文字コードに相当する範囲で出力したのであって、そうではないバイト列(ヌル等)でも問題なく出力することができる。
属性
ファイルの大きさ(ファイルサイズ)を得る
list.files関数で調べたいファイル名を取得し、file.info関数を使ってファイルの情報を得ればよい。file.info関数の戻り値はリストで、要素sizeにファイルの大きさがバイト単位で格納されている。以下の例のとおり、list.files関数にfull.namesオプションにTRUEを指定しないと、戻り値の各要素がNAで返されてしまうので注意。
以下は、ある環境下のC:\Windowsに置かれたファイル名が「w」で始まる拡張子がiniかexeのファイルの大きさを調べた例。
> fl <- list.files("C:\\Windows", "^w.+\\.(ini|exe)")
> file.info(fl)
size isdir mode mtime ctime atime exe
win.ini NA NA <NA> <NA> <NA> <NA> <NA>
winhlp32.exe NA NA <NA> <NA> <NA> <NA> <NA>
> file.info(fl)[1]
size
win.ini NA
winhlp32.exe NA
> fl <- list.files("C:\\Windows", "^w.+\\.(ini|exe)", full.names = TRUE)
> file.info(fl)[1]
size
C:\\Windows/win.ini 92
C:\\Windows/winhlp32.exe 12288
ファイルとディレクトリ
ファイルやディレクトリの存在を確認する
ファイルの存在の有無を確認するにはfile.exists関数を、フォルダーの場合はdir.exists関数を使う。Rはフォルダー(ディレクトリ)の区切りを示す記号に「¥」(円マーク)と「/」(スラッシュ)の両方を使うことができる。
> file.exists("C:/Windows/win.ini")
[1] TRUE
> file.exists("C:/Windows/win.inii")
[1] FALSE
> dir.exists("C:/Windows")
[1] TRUE
> dir.exists("C:/Windowss")
[1] FALSE
file.exists関数は、フォルダーを指定した場合、そのフォルダー名の最後に区切り記号を付けないとTRUEを返すので注意。
dir.exists関数はファイルであればFALSE、フォルダーであればTRUEを返す。
> dir.exists("C:/Windows")
[1] TRUE
> dir.exists("C:/Windows/")
[1] TRUE
> dir.exists("C:/Windows/win.ini")
[1] FALSE
ディレクトリ
カレントディレクトリを取得する
getwd関数を使う。インストール直後のスタートメニューからRを起動した状態で実行してみる。
> getwd()
[1] "C:/Users/○○/Documents"
○○にはアカウント名が入る。
これはスタートメニューからRを起動するとそのようになっただけであり、例えば既存の.RDataファイルをダブルクリックしてRを起動すれば、その.RDataを置いてあるディレクトリをカレントディレクトリとしてRは起動することになる。
カレントディレクトリを設定する
getwd関数を使う。
> getwd()
[1] "C:/Users/○○/Documents"
> setwd("C:/Users/○○/Pictures/")
> getwd()
[1] "C:/Users/○○/Pictures"
> setwd("C:/Users/○○/Picture/")
setwd("C:/Users/○○/Picture/") でエラー:
作業ディレクトリを変更できません
最後の例のとおり、存在しないディレクトリを指定するとエラーが発生する。
ディレクトリ内のファイル一覧を得る
list.files関数を使う。pathオプションにはファイル一覧を取得するディレクトリを指定する。patternオプションに何も指定しないと全てのファイルを返す。特定のファイルのみを取得したい場合は、正規表現でファイル名のパターンを指定する。
以下は、とあるWindows 10環境下で行った例。
> list.files(path = "C:/Windows/Fonts")
[1] "8514fix.fon" "8514fixe.fon"
[3] "8514fixg.fon" "8514fixr.fon"
(以下、表示省略)
> list.files(path = "C:/Windows/Fonts", pattern = "^ms")
[1] "msgothic.ttc" "msjh.ttc" "msjhbd.ttc" "msjhl.ttc" "msmincho.ttc"
[6] "msyh.ttc" "msyhbd.ttc" "msyhl.ttc" "msyi.ttf"
> list.files(path = "C:/Windows/Fonts", pattern = "^japan")
character(0)
ディレクトリ一覧を得る
list.dirs関数を使う。第一引数にディレクトリ一覧を得たいディレクトリを指定すると、どのディレクトリに含まれるサブディレクトリが得られる。ただし、デフォルトでは、その指定したディレクトリ自身と、再帰的に得られるサブディレクトリ内のサブディレクトリも含まれる。以下、実行例。
> list.dirs("C:/Program Files/Windows NT")
[1] "C:/Program Files/Windows NT"
[2] "C:/Program Files/Windows NT/Accessories"
[3] "C:/Program Files/Windows NT/Accessories/en-US"
[4] "C:/Program Files/Windows NT/Accessories/ja-JP"
[5] "C:/Program Files/Windows NT/TableTextService"
[6] "C:/Program Files/Windows NT/TableTextService/en-US"
[7] "C:/Program Files/Windows NT/アクセサリ"
指定したディレクトリ内のサブディレクトリだけを得るには、recursiveオプションにFALSEを指定する。
> list.dirs("C:/Program Files/Windows NT", recursive = FALSE)
[1] "C:/Program Files/Windows NT/Accessories"
[2] "C:/Program Files/Windows NT/TableTextService"
[3] "C:/Program Files/Windows NT/アクセサリ"
デフォルトでは絶対パスで表示されるが、full.namesオプションにFALSEを指定すると、第一引数に指定したディレクトリからの相対パスが得られる(指定したディレクトリは"")。
> list.dirs("C:/Program Files/Windows NT", full.names = FALSE)
[1] "" "Accessories" "Accessories/en-US"
[4] "Accessories/ja-JP" "TableTextService" "TableTextService/en-US"
[7] "アクセサリ"
> list.dirs("C:/Program Files/Windows NT", recursive = FALSE, full.names = FALSE)
[1] "Accessories" "TableTextService" "アクセサリ"
文字列型ベクトルを簡単にテキストファイルに出力する
cat関数を使う。sepオプションには文字型ベクトルの各要素の間に挟む文字列を指定する。以下の例では、最後のコマンドを実行後にはプロンプトは改行されないで表示される。