readr — 高速で柔軟なテーブル読み込み
タブ区切りテキストやCSVファイルを読み込んでdata.frameにするツール。
.gz
や .xz
などの圧縮ファイルも透過的に読み書き可能。
標準でも read.table()
や read.csv()
があるけど、それらと比べて
- 場合により数倍高速・省メモリ
- 列の名前や型を指定しやすい
- 指定した列だけ読み込むこともできる
- 生data.frameより安全な tibble として返してくれる
- 空白行を勝手にスキップする (1.2から
skip_empty_rows = TRUE
) - 勝手に列名を変更
しないする (2.0からname_repair = "unique"
) R 4.0 から標準関数もこの挙動。stringsAsFactors = FALSE
とイチイチ書かなくて文字列を読める
tidyverse に含まれているので、
install.packages("tidyverse")
で一括インストール、
library(tidyverse)
で一括ロード。
例えば:
library(conflicted)
library(tidyverse)
write_tsv(diamonds, "diamonds.tsv.gz")
read_tsv("diamonds.tsv.gz")
主な関数
ファイル読み込み
read_delim(file, delim,
quote = '"',
escape_backslash = FALSE,
escape_double = TRUE,
col_names = TRUE,
col_types = NULL,
col_select = NULL,
id = NULL,
locale = default_locale(),
na = c("", "NA"),
quoted_na = TRUE,
comment = "",
trim_ws = FALSE,
skip = 0,
n_max = Inf,
guess_max = min(1000, n_max),
name_repair = "unique",
num_threads = readr_threads(),
progress = show_progress(),
show_col_types = should_show_types(),
skip_empty_rows = TRUE,
lazy = TRUE)
read_csv(...)
や read_tsv(...)
は区切り文字 delim =
指定済みのショートカット。
read_table(...)
- 連続する空白文字をひとつの区切りと見なして処理
read_fwf(file, col_positions, ...)
- fixed width file. 第二引数の指定方法は
fwf_empty(infile, skip = 0, col_names = NULL)
で自動推定fwf_widths(widths, col_names = NULL)
で幅指定fwf_positions(start, end, col_names = NULL)
で開始・終了位置指定
read_lines(file, skip = 0, n_max = -1L, ...)
,read_lines_raw(...)
- 1行を1要素とした文字列ベクタとして読み込む
read_file(file)
- ファイルの内容まるごと文字列で返す
同じ形式の複数ファイルをvectorで渡せば、順に読み込んで rbind()
してくれる。
purrr::map(file, readr::read_csv) |> purrr::list_rbind(names_to = "file")
と同等だが、それよりも少し高速で、列の型推定もうまくいきやすい。
ただし names_to =
のように元のファイルとの関連を残すオプションは無い。
ファイルの中身を文字列として渡すことも可能。
自動で判別してもらえるけど I()
で包むのが確実。
content = "x,y\n1,a\n"
readr::read_csv(I(content))
x y
1 1 a
ファイル書き出し
標準の write.*()
関数をオプション無しで使うと、
左端に余計な列を追加したり、不要な"クオート"を追加したりする。
iris |> head(2) |> write.csv(stdout())
"","Sepal.Length","Sepal.Width","Petal.Length","Petal.Width","Species"
"1",5.1,3.5,1.4,0.2,"setosa"
"2",4.9,3,1.4,0.2,"setosa"
iris |> head(2) |> readr::write_csv(stdout())
Sepal.Length,Sepal.Width,Petal.Length,Petal.Width,Species
5.1,3.5,1.4,0.2,setosa
4.9,3,1.4,0.2,setosa
readr::write_*()
のデフォルトはそれよりだいぶマシだが、
欠損値を空欄ではなく NA
にしてしまうことだけ要注意。
空欄にするには毎回 na = ""
が必要。
write_delim(x, file,
delim = " ",
na = "NA",
append = FALSE,
col_names = !append,
quote = c("needed", "all", "none"),
escape = c("double", "backslash", "none"),
eol = "\n",
num_threads = readr_threads(),
progress = show_progress())
write_csv(...)
や write_tsv(...)
は区切り文字 delim =
指定済みのショートカット。
write_lines(x, file, sep = "\n", na = "NA", append = FALSE)
- vectorやlistを1行ずつ書き出す。
write_file(x, file, append = FALSE)
- 文字列をそのまま書き出す。
文字列から別の型へ
parse_number(x, na = c("", "NA"), locale = default_locale(), trim_ws = TRUE)
- 文字列で最初に登場する数値を抜き出す。
邪魔な文字が前後に入っていても大丈夫。
x = c("42", "1.293e2", "i18n", "24/7") readr::parse_number(x)
[1] 42.0 129.3 18.0 24.0
parse_double(x, ...)
- 文字列を実数型として解釈して返す。
"6e23"
のような指数形式も大丈夫。 異物が混じっていた場合は警告して欠損値扱い。readr::parse_double(x)
[1] 42.0 129.3 NA NA attr(,"problems") row col expected actual 1 3 NA a double i18n 2 4 NA no trailing characters 24/7
as.double(x)
[1] 42.0 129.3 NA NA
parse_double(x, ...)
,parse_integer(x, ...)
- 文字列を整数型として解釈して返す。
小数点などを含む文字列は警告して欠損値扱い。
readr::parse_integer(x)
[1] 42 NA NA NA attr(,"problems") row col expected actual 1 2 NA no trailing characters 1.293e2 2 3 NA no trailing characters i18n 3 4 NA no trailing characters 24/7
as.integer(x)
[1] 42 129 NA NA
標準の
as.integer()
が1ではなく129を返すということは、 一旦実数型で読み取ったあと小数点以下を切り捨ててるっぽい。 parse_logical(x, ...)
- 特定の文字列を論理値型として解釈。
大文字小文字は問わない。
“0以外の数字はtrue” のような数値型からの変換規則とは異なる。
T
,F
をTRUE
,FALSE
扱いしてしまうことに注意。readr::parse_logical(c("1", "0", "t", "f", "TRUE", "FALSE", "2"))
[1] TRUE FALSE TRUE FALSE TRUE FALSE NA attr(,"problems") row col expected actual 1 7 NA 1/0/T/F/TRUE/FALSE 2
as.logical(c("1", "0", "t", "f", "TRUE", "FALSE", "2"))
[1] NA NA NA NA TRUE FALSE NA
as.logical(c(-1, 0, 1, 2))
[1] TRUE FALSE TRUE TRUE
parse_factor(x, levels, ordered = FALSE, ...)
parse_date(x, format = "", ...)
,
parse_datetime(x, format = "", ...)
,
parse_time(x, format = "", ...)
列の型を指定する
https://cran.r-project.org/web/packages/readr/vignettes/column-types.html
基本的には何も指定しなくても数値などを認識していい感じに設定してくれる。 文字列を勝手にfactorに変換したりはしない。 整数と実数は区別せずnumeric型で読む(1.2から)。
明示的に型を指定したい場合は col_types
引数に cols()
関数の値を渡す。
文字列で "ccdi_"
のように省略することも可能。
read_csv("mydata.csv", col_types="ccdi_")
colsp = cols(length=col_double(), count="i", .default="c")
read_csv("mydata.csv", col_types=colsp)
[c] col_character()
: 文字列[i] col_integer()
: 整数[d] col_double()
: 実数[l] col_logical()
: TRUE or FALSE[D] col_date(format = "")
: 日付[t] col_time(format = "")
: 時間[T] col_datetime(format = "")
: 日付[n] col_number()
: 数字以外の文字が含まれていても無視して数字として返す[?] col_guess()
: 推測[_] col_skip()
: 列を読まないcol_factor(levels, ordered)
: factor
指定した列だけ読むには cols(..., .default = col_skip())
とするか cols_only(...)
を使う。
設定
最近ちょっと表示がおせっかい過ぎるので ~/.Rprofile
で設定を直す:
options(
readr.num_columns = 0L,
readr.show_col_types = FALSE,
readr.show_progress = FALSE
)
read::read_*()
で読み込んだばかりのtibbleは各列の型情報を含んだ
spec_tbl_df
という特殊なサブクラスになっている。
この機能を切るオプションは用意されていない。
すぐに普通のtibbleが欲しい場合は []
で空subsettingするのが手軽。
data = readr::readr_example("mtcars.csv") |> readr::read_csv()
class(data)
[1] "spec_tbl_df" "tbl_df" "tbl" "data.frame"
class(data[])
[1] "tbl_df" "tbl" "data.frame"
Excelファイルを読み込む
https://github.com/tidyverse/readxl
自分のデータは絶対にExcel形式ではなくCSVやTSV形式で保存すべきだが、
人から受け取ったファイルや論文のサプリデータがExcelだったら仕方がない。
readxl
というパッケージを利用すれば、
一旦Officeで開いてCSVに変換するという手間なしで直接Rに読み込める。
Rの中から install.packages("readxl")
でインストールし、
使う前に library(readxl)
でパッケージを読み込む。
excel_sheets(path)
- ファイルに含まれるシートの名前を取得
read_excel(path, sheet = 1, col_names = TRUE, col_types = NULL, na = "", skip = 0)
.xls
とxlsx
のどちらの形式でも読める。sheet
は番号でも名前でもいい。 それ以降の引数についてはreadr
の関数と同じ。
tibble
tbl_df
クラスが付与された改良版data.frameのことをtibbleと呼ぶ。
readr で読み込んだデータもこの形式になる。
tbl_mtcars = as_tibble(mtcars)
class(tbl_mtcars)
[1] "tbl_df" "tbl" "data.frame"
class(mtcars)
[1] "data.frame"
生のdata.frameとの違いは:
-
巨大なデータをうっかり
print()
しても画面を埋め尽くさない。 (逆に全体を見たい場合は工夫が必要。後述)print(tbl_mtcars)
mpg cyl disp hp drat wt qsec vs am gear carb 1 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4 2 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4 -- 31 15.0 8 301 335 3.54 3.570 14.60 0 1 5 8 32 21.4 4 121 109 4.11 2.780 18.60 1 1 4 2
-
列名の部分一致で良しとしない。 例えば
mtcars$m
は黙ってmpg列vectorを返してしまうが、tbl_mtcars$m
は警告つきNULL
。mtcars$m ## [1] 21.0 21.0 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 17.8 16.4 17.3 15.2 10.4 10.4 14.7 32.4 30.4 33.9 21.5 15.5 15.2 13.3 19.2 27.3 26.0 30.4 15.8 19.7 15.0 21.4 tbl_mtcars$m ## Warning: Unknown or uninitialised column: `m`. ## NULL
-
型に一貫性があり、勝手に
drop = TRUE
しない。 例えばmtcars[,"mpg"]
はvectorになってしまうが、tbl_mtcars[,"mpg"]
はtibbleのまま。 vectorが欲しい場合は二重四角括弧tbl_mtcars[["mpg"]]
。mtcars[,"mpg"] # implicit drop = TRUE
[1] 21.0 21.0 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 17.8 16.4 17.3 15.2 10.4 10.4 14.7 32.4 30.4 33.9 21.5 15.5 15.2 13.3 19.2 27.3 26.0 30.4 15.8 19.7 15.0 21.4
tbl_mtcars[,"mpg"] # remains tibble
mpg 1 21.0 2 21.0 -- 31 15.0 32 21.4
-
行の名前は使わない。 行の名前として保持されている情報を使いたい場合は
rownames_to_column()
とかrowid_to_column()
で独立した列にしておく必要がある。
新しいtibble 1.4以降では
pillar
というパッケージが有効数字や欠損値などの表示形式を勝手にイジるようになってしまった。
見やすくない上に遅いので私は registerS3method()
で上書きしている。
関数
tibble::tibble(...)
- tibbleを新規作成。ちょっと昔までは
dplyr::data_frame()
だった。 base::data.frame()
と違ってバグが混入しにくくて便利:- 勝手に型変換しない (
stringsAsFactors = FALSE
が基本) - 勝手に列名を変えない
- 長さ1の変数以外はリサイクルしない
- 引数の評価がlazyに行われるので前の列を利用して後の列を作ったりできる
tbl_df
クラスを付加- ただし1.4以降のバージョンでは表示が遅くて見にくい
- 勝手に型変換しない (
tibble::as_tibble(x)
- 既存のdata.frameやmatrixをtibbleに変換。
ちょっと昔までは
dplyr::tbl_df()
とかdplyr::as_data_frame()
だった。 v2.0からは列名がちゃんとついてないとエラーになる。 tibble::new_tibble(x, ..., nrow, class = NULL)
- tibbleのサブクラスを扱う開発者向け
as_tibble()
。 検証なし、nrow
必須の代わりに高速。 クラスを先頭に追加できるのも便利。 tibble::enframe(x, name = "name", value = "value")
- 名前付きvectorとかlistを2列のtibbleに変換する。
tibble::deframe(x)
はその逆。c(a = 1, b = 2) |> enframe() |> deframe()
tibble::add_row(.data, ..., .before = NULL, .after = NULL)
- 既存のtibbleに新しいデータを1行追加する。
tibble::rownames_to_column(df, var = "rowname")
- 行の名前をcharacter型で1列目の変数にする。
dplyr::add_rownames()
の後継。 tibble::rowid_to_column(df, var = "rowid")
はそれを整数で。tibble::column_to_rownames(df, var = "rowname")
はその逆。tibble::remove_rownames(df)
は消すだけ。tibble::glimpse(.data, width = NULL)
- データの中身をざっと見る。
print()
とかstr()
のようなもの。 pillar::type_sum(x)
- オブジェクトの型
pillar::obj_sum(x)
type_sum
とサイズ e.g.,"data.frame [150 x 5]"
設定
表示される行数や幅を調節する項目には以下のようなものがある。
~/.Rprofile
に書いておけば起動時に勝手に設定される。
height = 30L # for example
width = 160L
options(
pillar.neg = FALSE,
pillar.subtle = FALSE,
pillar.print_max = height,
pillar.print_min = height,
pillar.width = width,
width = min(width, 10000L)
)
- https://github.com/r-lib/pillar/blob/main/R/options.R
- https://github.com/tidyverse/tibble/blob/main/R/options.R
大きいtibbleの全体を表示する
普通に print()
すると大きいtibbleの全体が見えない。
print()
関数にオプションを指定したり utils::page()
を利用したりする必要がある。
RStudioやVSCodeを使っている場合は View()
でスプレッドシートのように閲覧可能。
# pillar:::print.tbl()にオプションを渡す方式
diamonds |> print(n = Inf, width = Inf)
diamonds |> page("print", n = Inf, width = Inf)
# 標準data.frame用のprint()を呼ぶ方式
diamonds |> base::print.data.frame(max = .Machine$integer.max)
オプションをいちいち設定しなくて済むように
max_print()
,
less()
のような関数を定義しておくのもよい。
getOption("max.print")
の初期値は99999だがRStudioでは勝手に1000まで下げられる。