須通り
Sudo Masaaki official site
For the reinstatement of
population ecology.

おまえが長くtidyverseを覗くならば、tidyverseもまた等しくおまえを見返すのだ。

重要事項:Tidyverse は2018年現在もリアルタイムで基本機能の追加・改訂が進んでいるホットな関数群です。このサイトの記事のみならず公式ヘルプの内容ですら、将来バージョンで非推奨になったり機能廃止になる可能性が多分にあります。実際の業務で使用する際は常にオンラインの最新ドキュメントを確認しましょう。

tidyr: Easily Tidy Data with 'spread()' and 'gather()' Functions

dplyr: A Grammar of Data Manipulation

readr: Read Rectangular Text Data

magrittr: A Forward-Pipe Operator for R

purrr: Functional Programming Tools

tibble: Simple Data Frames

knitr: A General-Purpose Package for Dynamic Report Generation in R

ホーム | 統計 Top | これまでの記事で扱ったTidyverse関数のあんちょこ

不定期更新。使用頻度が最も高い関数群に絞って、引数の詳細な指定法をニホンゴで解説する方針。本来のヘルプドキュメントからの意訳なので注意。掲載済みの記事から抜書しているので時々文脈が不明。掲載順や説明文をスドウくんの一存で変える場合あり。

目次

  1. tidyr
    • データフレームの列を集約して long 形式にする tidyr::gather 関数
    • データフレームの列の内容を展開して wide 形式にする tidyr::spread 関数
    • データ列ラベルを分割する tidyr::separate 関数
    • データ列ラベルを高度な正規分割表現に従って分割する tidyr::extract 関数
    • データ列ラベルを単純結合する tidyr::unite 関数
    • 複数のデータ列のユニークな組み合わせを返す tidyr::expand 関数
    • データフレームの変数組み合わせの欠損行をNA(or指定文字列)で補完する tidyr::complete 関数

    後は nest(), unnest() かな。これ説明するのがすげえめんどくさい

  2. dplyr
    • 複数の tidy なデータフレームの合意データを作る dplyr::*_join 関数ファミリー
    • 列の構成が等しい2つのデータフレームからの、一致行ないし非一致行の絞り込み
      観測データの積集合を返す dplyr::intersect(x, y) 関数
      観測データの和集合を返す dplyr::union(x, y) 関数
      x にはあるが y にない行を返す dplyr::setdiff(x, y) 関数
    • データフレームの行を条件で絞り込む dplyr::filter 関数
    • データフレームの列を条件で絞り込む dplyr::select 関数
    • データフレームの列を改名する dplyr::rename 関数
    • データフレームの行を並べ換える dplyr::arrange 関数
    • データフレームの行ごとにデータを操作する dplyr::mutate() 関数
    • データフレーム中の条件指定した列を一括で mutate する dplyr::mutate_at() 関数と dplyr::mutate_if() 関数
    • 処理対象列の処理後の姿だけをデータフレーム中に残しつつ mutate する dplyr::transmute() 関数

    あと group_by(), do(), ungroup(), summarise(), sample_n(), sample_frac() 辺りを書いて一段落。

  3. 演算子 この節は未整理
    • magrittr::%>%(パイプ演算子)
    • magrittr::%T>%(Tee演算子)
  4. データ構造 当然必要だが解説未執筆
    • tibble(tibble)

tidyr


データフレームの列を集約して long 形式にする
tidyr::gather(data, key, value, ..., na.rm = FALSE, convert = FALSE, factor_key = FALSE)

省略不可な引数
data    処理対象のデータフレーム。
key    変換後のデータフレームに新規生成すべき key 列(=カテゴリのこと)の名前を指定。引用符で囲む必要はない。
value    変換後のデータフレームに新規生成すべき value 列(=データの値)の名前を指定。引用符で囲む必要はない。
...    変換前のデータフレームにある、Long形式にまとめてしまいたい列の名を(引用符なしで)1つ以上指定。
    変換後のデータフレームにおいて、指定された列の列名が key 列に格納され、データが value 列に格納される。
    変換前のデータフレームにある x から z までの間の全列を含めたい場合は x:z などとする。
    列 y を除外したければ -y などとする。さらなる詳細は dplyr::select() のドキュメントを参照。

オプション扱いの引数
na.rm    TRUE であるとき、value列が NA となるデータ行がもしあれば削除される。
convert    TRUEであるとき、 key 列に含まれるデータを自動で型変換する。元の列名が numeric, integer, or logical であるときに便利。
factor_key    デフォルトはFALSEで、key列の値は文字列ベクトルで格納される。TRUEであるとき、factor型に変換される。このとき元のデータフレームにおける列の順序が保存される。

データフレームの列の内容を展開して wide 形式にする
tidyr::spread(data, key, value, fill = NA, convert = FALSE, drop = TRUE, sep = NULL)

省略不可な引数
data    データフレーム。
key     分類のキーとして用いる。元データに含まれる列を名前で指定。引用符で囲む必要はない。ここに格納されている値の水準数だけ、新しいデータ列が作られ、そこにvalueで指定したデータが格納される。
value    上記で分類したセルをpopulateするためのvalue。元データに含まれる列を名前で指定。引用符で囲む必要はない。

オプションの引数
fill    変換後のカテゴリに対応するデータ行が存在しないとき、ここに指定した値で置き換える。なお元データの該当行にNAが入っている場合も、ここで指定した値に置換される。
convert    TRUEであるとき、分類の結果生成された各列に対して、type.convert() 関数が as.is=TRUE として実行される。元の列に含まれている各変数が、複数のデータ型を文字列にまとめたものである場合にとりわけ有用。もし元のクラスがfactorないしdateであった場合、新たに生成される列は自動では同じ型として保存されないので、いったんcharacterにまとめてから変換する必要がある。
drop    FALSEであるとき、新しく生成されるfactor型のデータ列において存在しない水準は削除される。
sep    NULLであるとき、新たに生成される列の名前を key 列に格納されている変数の値そのものとして生成する。NULL以外であれば、<key_name><sep><key_value> という命名規則で作られる。

データ列ラベルを分割する
tidyr::separate( data, col, into, sep = "[^[:alnum:]]+", remove = TRUE,
          convert = FALSE, extra = "warn", fill = "warn", ...)

引数
data    データフレーム。
col    分割対象とするデータ列の名前、もしくはアドレス(何番目の列かを表す数値)。tidyselect::vars_pull() に渡される。引用符で囲む必要はない。
into    新しく作られる変数(複数ある)の名前を文字列ベクトルで指定。

sep    データ列の分割場所となる文字(セパレータ)。分割規則を文字列で与えるか、何番目の文字までを切り取るかを整数ベクトルとして指定する。
    文字列で与えた場合は正規表現として解釈される。デフォルトの "[^[:alnum:]]+" はアルファベットと半角数字以外、全ての文字で列を分割しようとする。
    数値(須藤注:整数ベクトル)で与えた場合は、正数であれば左から数えて(負数であれば右から)n 字までを切り取り、n+1字目から次の列が始まるよう分割される。sep 引数のベクトル要素は into の要素数より1つだけ少なく与えられるべきものである。

オプションの引数
remove    デフォルトは TRUE で、分割対象になった元のデータ列は関数の出力ファイルから取り除かれる。
convert    デフォルトはFALSEだが、もしも TRUE ならば、変換生成後のデータ列に type.convert() を as.is = TRUE として掛ける。元のデータが integer, numeric or logical であるときに有用。

extra    If sep is a character vector, this controls what happens when there are too many pieces. There are three valid options:
    "warn" (the default): emit a warning and drop extra values.
    "drop": drop any extra values without a warning.
    "merge": only splits at most length(into) times

fill    If sep is a character vector, this controls what happens when there are not enough pieces. There are three valid options:
    "warn" (the default): emit a warning and fill from the right
    "right": fill with missing values on the right
    "left": fill with missing values on the left
...    Additional arguments passed on to methods.

データ列ラベルを高度な正規分割表現に従って分割する
tidyr::extract(data, col, into, regex = "([[:alnum:]]+)", remove = TRUE, convert = FALSE, ...)

引数
data    データフレーム。
col    分割対象とするデータ列の名前もしくは場所(何番目の列か)。tidyselect::vars_pull() に渡される。引用符で囲む必要はない。
into    新しく作られる変数(複数ある)の名前を文字列ベクトルで指定。

regex    望ましい名前ラベルを抽出するための正規表現を1つ指定する。この正規表現に含まれるグループ(正規表現では () で囲むことで定義される)が、引数 into に入れた各要素と一対一対応する必要がある。

オプションの引数
remove    デフォルトは TRUE で、分割対象になった元のデータ列は関数の出力ファイルに含まれない。
convert    デフォルトはFALSE。もしも TRUE ならば、変換生成後のデータ列に type.convert() を as.is = TRUE として掛ける。元のデータが integer, numeric or logical であるときに有用。
...    正規表現を処理するため、regexec() に渡したい追加の引数があれば。

データ列ラベルを単純結合する
tidyr::unite(data, col, ..., sep = "_", remove = TRUE)

引数
data    データフレーム。
col    結合して作られる新たな列名。文字列ないしシンボルで与える。"" で囲んでも囲まなくてもいい。rlang::quo_name() の規則に従って渡されるが、実際のオブジェクトに対応しないシンボル名での指定は現在の tidyverse では非推奨であり、後方互換性のためだけに残されている。
...    結合対象の列を指定。何も指定しない場合、全データ列を選択。列名は "" で囲んでも囲まなくてもいい。列 x と列 z の間にある全てを選びたければ x:z としてよい。-y とすれば列 y を除外する。さらに詳細は dplyr::select() のドキュメントを参照。
sep    結合したデータの間に入るセパレータ文字列。デフォルトは "_" で、たとえば "Control_Before" などとなる。
remove    デフォルトは TRUE で、結合対象になった元のデータ列は関数の出力ファイルに含まれない。

複数のデータ列のユニークな組み合わせを返す
tidyr::expand(data, ...)

省略不可な引数
data    処理対象のデータフレーム。
...    どの列を expand するかの指定。

たとえば df という名のデータフレーム中に存在する列 x, y, z の各水準に対して、実際の df に欠けているものを含めて全てのユニークな組み合わせを作成するには
expand(df, x, y, z)
とすればいい。

####

サブ機能を提供する関数
crossing(...)
nesting(...)

crossing() は R の標準関数 expand.grid() とほぼ同じ機能を提供するが、文字列を factor 型データに変換することはしない。
nesting() は crossing() と相補的な働きをする関数で、crossing() が各変数の有する水準について、想定しうる全組み合わせを作るのに対し、nesting() は既にデータ中に存在する組み合わせのみを返す。

実際の df に含まれている x, y, z の組み合わせのみについて、重複を無くして列挙したいならば
expand(df, nesting(x, y, z))
として、対象の変数を nesting() で括る。

expand(df, nesting(x, y), z)
であれば、x と y については既存の組み合わせだけが抽出され、それらと z との間では想定しうる全組み合わせが作成される。

なお数値データ列に対しては、 year=2010:2020 とか year=full_seq(year, 1) などとして連続データを手動で割り付けることも可能。

データフレームの変数組み合わせの欠損行をNA(or指定文字列)で補完する
tidyr::complete(data, ..., fill = list())

省略不可な引数
data    処理対象のデータフレーム。
...    どの列を expand するかの指定。指定方法は expand(data, ...) と同じ。

オプションの引数
fill    名前付きリスト。名称で指定した各変数に対して、データが存在しない組み合わせ=欠損値を埋める値を指定。特段に指定しなければ NA になる。

dplyr


複数の tidy なデータフレームの合意データを作る
dplyr::inner_join(x, y, by = NULL, copy = FALSE, suffix = c(".x", ".y"), ...)
dplyr::left_join(x, y, by = NULL, copy = FALSE, suffix = c(".x", ".y"), ...)
dplyr::right_join(x, y, by = NULL, copy = FALSE, suffix = c(".x", ".y"), ...)
dplyr::full_join(x, y, by = NULL, copy = FALSE, suffix = c(".x", ".y"), ...)
dplyr::semi_join(x, y, by = NULL, copy = FALSE, ...)
dplyr::anti_join(x, y, by = NULL, copy = FALSE, ...)

省略不可な引数
x, y    結合したい2つのテーブル

オプションの引数
by    2つのテーブル間で共通の変数に対応する、列の名前を格納した文字列ベクトル。デフォルトは NULL であり、*_join() 関数はいわゆる "natural join"、すなわち2つのテーブルにおいて共通の列名が付いている変数全てを用いた、行のマッチングを実行する(須藤注:要するに、byに複数の列を指定したとき、値が完全一致する行同士を結合する)。byの中身を明示的に指定しなかった場合には、どの列を用いて join したかを通知するメッセージが出力される。
もしテーブル x と y で、同じ内容が異なる列名で保持されている場合は、たとえば by=c("a"="b") などとして名前付きベクトルで指定することで x.a と y.b をマッチさせることができる。

copy    もし x と y が異なるデータソース(これはRのインターフェースから SQL データベースに接続して使っている場合のことを指す)に基づいており、かつ copy=TRUE であるとき、 y の内容が x の属するデータベース(src)へコピーされる。これは潜在的に時間やメモリをバカ食いしうる操作であり、必要な場合だけ行うこと。

suffix    x, y に共通する名前の変数があったにもかかわらず by で指定されなかったとき、結合後のデータフレームにおける列名の重複を避けるために付ける接尾辞。長さ2の文字列ベクトルで指定。デフォルトでは出自に基づいて hoge -> hoge.x or hoge.y となる。

...    渡したい追加の引数があれば。

分かる人のための蛇足:もし x が dplyr::group_by() で層別された tibble である場合には、joining 最中には grouping は考慮されないが、最終的に生成されるデータには x に準拠した grouping が保持される。便利である。

####

結合タイプ

left_join()    列については「(xにある列)と(yにある列)の和集合」として全て保持される。行については、xの現存する行は全て保持される。byで指定した列の組み合わせが x⊃y であれば、対応する y 側データの無い行が発生することになり、そのようなセル(以下の例では plays の Mick)には NA が挿入される(須藤注: x⊂y であれば、y側にしか存在しない行のデータは挿入されない)。
もしも完全一致する行が複数存在する場合は、念のため (xのbyで指定されない列) と (yのbyで指定されない列) の全コンビネーションが作られる。

right_join()    left_join() の x と y の力関係を入れ替えたもの。(須藤注:だったら left_join() だけを、x と y を入れ替えて使えばいいじゃん?と思うかもしれない。まあ裸でこの関数を使う場合はその通り。だが実用的にはパイプライン中で、x を予め加工した後に %>% right_join(y) として流し込むことがあり、この用途は left_join() では代替できないのだ。)

inner_join()    列については「(xにある列)と(yにある列)の和集合」として全て保持される。行については(xのby指定列)と(yのby指定列)が完全一致する場合のみ、合併対象となる。もしも完全一致する行が複数存在する場合は、(xのbyで指定されない列)と(yのbyで指定されない列)の全コンビネーションが作られる。

semi_join()    xの行のうち、yにも共通列が存在するものだけを残す処理。yからのデータは保持されず、判定のみに用いられる。

# なお inner_join() と semi_join() の違いとして、仮に x のある行に対応する y の行が複数存在したとき、inner_join() では x の行が複製されるが、semi_join() ではそのようなことは起こらない。
# semi_join はデータの結合というよりも、x を y との共通項でスクリーニングする処理。

anti_join()    xの行のうち、yに対応行が存在しないものを抽出する処理。要するに semi_join() の y に関する余事象。

full_join()    x および y に存在するデータ行および列を全て保持しつつ合意データを作る。対応する行がもう片方にない列については、NA で補完する。

2つの(列の構成が等しい)データフレームからの、一致行ないし非一致行の絞り込み
(filtering join, set operations と呼ばれる機能)

dplyr::intersect(x, y): # 観測データの積集合、すなわち両方のデータフレームに存在する行のみを抽出する
dplyr::union(x, y): # 観測データの和集合、すなわち両データフレームを縦に結合してから、重複行を削除したものを出力する
dplyr::setdiff(x, y): # x にはあるが y にない行を返す。これのみ引数の順番が結果に影響する。

データフレームの行を条件で絞り込む
filter(.data, ...)

省略不可な引数
.data    絞り込み対象とする tbl 形式のテーブルデータ。正確に言うと filter() やそれに類する関数は S3 クラスの総称関数であり、与えた .data の型たとえば tbl_df() や dtplyr::tbl_dt() や dbplyr::tbl_dbi() などに応じて内部的に対応する関数がある(つまり外部データベースから持ってきたデータも処理対象にできるということ。気になる人は各自勉強)。

...    .data 内の変数において、絞り込み条件を与える論理述語(logical predicates)。複数条件は & で繋いで指定することができる(須藤注:ただし複数条件をコンマ , で繋いでも AND 条件になるし、その方が一般的だと思う。なお OR 条件は | でつなぐ)。とどのつまり .data の行数と同じ長さの真偽値ベクトルになればおk。最終的にTRUEの行が抽出対象となる。

なお ... 以下で指定した引数は、自動的に "" で囲まれてから、データフレームのコンテクスト内で評価される。ただし unquoting や splicing はサポートされている。これらの概念については vignette("programming") を参照。

たとえば、どの変数がどのスコープで定義されているかによって、 filter(df, x==y) は以下の4通りに解釈されうる。

df[df$x == df$y, ] # x, y がいずれも df の列名である。
df[df$x == y, ] # x は df の列名であるが、 y は df とは無関係のデータオブジェクトである。
df[x == df$y, ] # y は df の列名であるが、 x は df とは無関係のデータオブジェクトである。
df[x == y, ] # x, y ともに df とは無関係のベクトルオブジェクトであり、単に x 要素と y の同じ位置の要素が一致したか否かで判定される。

データフレームの列を条件で絞り込む。第2引数以下で指定されなかった列は削除される。
select(.data, ...)

データフレームの指定した列を改名する。非指定列も全て残される。
rename(.data, ...)

省略不可な引数
.data    絞り込み対象とする tbl 形式のテーブルデータ。filter() のときと同じく総称的である。

...    .data において列の絞り込み条件を与える1つ、ないしはコンマで区切られた複数の expression。変数の名前を、あたかもそれが何列目かを指定する数字(position)であるかのように扱うことができる。この数字が正であれば、その順番に対応する列が残される。数字にマイナスを付けると、対応する順番の列は削除される。

もし最初の expression が負だったら、select() 関数は自動的に全ての変数を残す設定に切り替わってから、続く expression の評価を開始する(須藤注:デフォルトでは、select() 関数は最初にどの変数も残さない状態から評価をスタートし、expression で明示的に指定された変数だけを拾って出力する)。

絞り込み条件を与える expression を named arguments、すなわち左辺に文字列が入るよう = で繋げば、指定した文字列で変数をリネームできる。

なお ... 以下で指定した引数は、自動的に "" で囲まれてから、列の名前が列のポジションを表すように、データフレームのコンテクスト内で評価される。ただし unquoting や splicing はサポートされている。これらの概念については vignette("programming") を参照。

arrange(.data, ...)
arrange(.data, ..., .by_group=FALSE) # データが grouped_df であったときに対応するメソッド

省略不可な引数
.data    並べ替え対象とする tbl 形式のテーブルデータ。S3 クラスの総称関数であり、与えた .data の型、たとえば tbl_df() や dtplyr::tbl_dt() や dbplyr::tbl_dbi() などに、それぞれ内部的に対応する関数がある。

...    並べ替え条件に用いたい列を、"" で囲わない列名として与える。複数の場合は、コンマで区切って与える。ここに挙げた優先順に、その変数について昇順になるようにデータ行が並べ替えられる(要するに2番目以降の条件は、タイが発生したときの判定基準としてのみ用いられる)。ただし desc() で囲った変数があれば、その変数だけは降順になるよう並べ替えられる。

.by_group    第一引数に grouped_df 型のデータを入れたときの追加引数。もしも TRUE であれば、最初に所与の grouping variable でソートしてから式評価を開始する。
デフォルトは FALSE。

tidyなデータフレームの行ごとにデータを操作する
mutate(.data, ...)

省略不可な引数
.data    絞り込み対象とするテーブル形式のデータ。

...    行いたい処理。複数あればコンマで区切る。
(新しい列名)=(ここに処理内容) とすれば、.data に新しい列を追加できる。
(もともとあった列名)=(ここに処理内容) とすれば、元々 .data にあった列の内容を書き換えられる。
(もともとあった列名)=NULL としてヌルを代入すれば、.data から列を削除する操作になる。

データフレーム中の条件指定した列を一括で mutate する
mutate_all(.tbl, .funs, ...)
mutate_if(.tbl, .predicate, .funs, ...)
mutate_at(.tbl, .vars, .funs, ..., .cols = NULL)

全ての関数で省略不可な引数
.tbl    操作対象の列を含むテーブル形式のデータ。

.funs    対象の列に対して行う操作。リストにまとめられた関数呼び出し(funs() 関数で生成される)として与えるか、関数の名前を文字列ベクトルとして列挙する。もしくは単純に1つだけ関数を与える。
(以下直訳)複数の formula を裸で与えると rlang::as_function() へ渡され、purrr スタイルのラムダ式になる。こうして生成されるラムダ式においては hybrid evaluation from happening ができないため、ラムダ式で処理内容を与えるよりも mean() 等の関数を直接与えるほうが、計算効率は良い。

...    .funs の関数呼び出し時に与える追加の引数がもしあれば。いずれも一度しか評価されない。tidy-dots サポートあり。何のことやらという人は以下を見よ。
https://www.rdocumentation.org/packages/rlang/versions/0.2.1/topics/tidy-dots

関数特異的な引数

.predicate    mutate_if() 関数において、対象列を絞り込むための選択基準を与える。叙述関数(predicate function: bool型の評価結果を返す関数のこと)、もしくはどの列を選択する/しないをダイレクトに記述した logical vector。mutate_if() 関数においては、この .predicate が TRUE であるところの変数が処理の対象に選ばれる。
この引数は rlang::as_function() に渡されるため、quosure スタイルのラムダ式や、関数の名前を "" で括って文字列形式で与えるということも可能である。

.vars    mutate_at() 関数において、対象列を絞り込むための選択基準を与える。vars() 関数によって生成されるリスト、もしくは列の名を並べた文字列ベクトル、さらには何番目の列を対象とするかを示す数値ベクトルとして与えることもできる。

.cols    旧いバージョンの mutate_at() では .vars の替わりに .cols と呼んでいた。つまり .cols=c("hoge", "huga") などとしても対象列を指定できるが、dplyr の文法の統一性を図るため非推奨である。

処理対象列の処理後の姿だけをデータフレーム中に残しつつ mutate する
transmute(.data, ...)
transmute_all(.tbl, .funs, ...)
transmute_if(.tbl, .predicate, .funs, ...)
transmute_at(.tbl, .vars, .funs, ..., .cols = NULL)

演算子

パイプ演算子 %>% のこと

%>% は「パイプ演算子」。現在は tidyverse に統合済みの magrittr というパッケージにて提供されている(なおパイプ自体はR言語に限った機能ではない)。簡単にいうと、パイプ演算子の左辺にあるデータを、右辺の関数の第一引数に代入して実行しませい、という指示を出す。従って右辺の関数は第二引数以降を括弧内に書くことになる。


T> は Tee演算子。正確には tidyverse::magrittr に属する。

library(tidyverse) の一括ロードには今のところ含まれていない。

Pipe a value forward into a function- or call expression and return the original value instead of the result. This is useful when an expression is used for its side-effect, say plotting or printing. The tee operator works like %>%, except the return value is lhs itself, and not the result of rhs function/expression.

普通のパイプ %>% だけで繋いでいる間は画面に何も出ない。パイプ処理も繋ぎつつ、途中で副作用として標準出力に出したい場合は、 %T>% で繋ぐ。
lhs %T>% rhs

ただし
lhs    A value or the magrittr placeholder.
rhs    A function call using the magrittr semantics.

では、今回はここまで。


# いったん、ここまでのデータを保存する。
today <- "180209"
save( list=ls(), file=paste("tidy", today, "dat", sep=".") ) # ワークスペースをバイナリ形式で

# よみこみ
today <- "180209"
load( file=paste("tidy", today, "dat", sep=".") )