概要
ふと思いついたのでやってみたが時間がかかったわりにあまりおもしろくなかった.
ところで私は最近のRの参考書を全然読んでない. 今回のネタがそういう最近の本に既に書いてある話だったら申し訳ない.
初めに
data(iris)
など, data()
関数は動作確認に使えるサンプルデータを取り出せる. しかし全部のデータセットを把握するのは難しいしする必要もあまりないので, 簡単に一覧を確認する方法を紹介する.
答えは
data()
だけである. これで一覧表示できる. package=
で指定したパッケージが提供するもの一覧に絞ることもできる…… まあそれだけでわざわざこうやってブログを書いたりしない.
本題
ここからが本題. インストールしたパッケージが多いと膨大になり, どれを選べばよいかわからなくなる. データセットを指定しないとき, data()
関数が返す packageIQR
オブジェクトはRStudio だと新しいタブとして開かれる. しかしこれだと検索しづらい. そこで, matrix
型で一覧情報が入っている results
要素を取り出す. これもそのままだと見づらいので tidyverse
を使って tibble
に変換する. 私の場合はこんな感じになる.
require(tidyverse) as_tibble(data()$results)
# A tibble: 242 x 4 Package LibPath Item Title <chr> <chr> <chr> <chr> 1 ggthemes /home/ill/R/x86_64-pc-linux-gnu-library/3.6 canva_palettes 150 Color Palettes from Canva 2 ggthemes /home/ill/R/x86_64-pc-linux-gnu-library/3.6 ggthemes_data Palette and theme data 3 forcats /home/ill/R/x86_64-pc-linux-gnu-library/3.6 gss_cat A sample of categorical variables from the General Social survey 4 stringr /home/ill/R/x86_64-pc-linux-gnu-library/3.6 fruit Sample character vectors for practicing string manipulations. 5 stringr /home/ill/R/x86_64-pc-linux-gnu-library/3.6 sentences Sample character vectors for practicing string manipulations. 6 stringr /home/ill/R/x86_64-pc-linux-gnu-library/3.6 words Sample character vectors for practicing string manipulations. 7 dplyr /home/ill/R/x86_64-pc-linux-gnu-library/3.6 band_instruments Band membership 8 dplyr /home/ill/R/x86_64-pc-linux-gnu-library/3.6 band_instruments2 Band membership 9 dplyr /home/ill/R/x86_64-pc-linux-gnu-library/3.6 band_members Band membership 10 dplyr /home/ill/R/x86_64-pc-linux-gnu-library/3.6 starwars Starwars characters
これで filter()
を使ってキーワード検索ができる. しかしこれだけだとパッケージ, インストール場所, データ名と簡単な概要しか分からない. そこで, 各データセットに対応するヘルプからもう少し詳細な情報を引っ張ってくる. ?
や help()
で個別に調べればいい話なのだが, せっかく tidyverse
で一覧を読み込んだのでまとめてやってしまおう. R のヘルプは Rd
というフォーマットで書かれており, そのなかでデータセットの形式は format
というセクションで書くというルールがある (絶対守られているかは怪しい). そこで対応する Rd ドキュメントの format を取り出せるようにする.
しかし, ここが少し厄介で, 結局 tidyverse
に加えて rvest
, shiny
が必要になった. 以下の make_help_Rd()
はデータ・セット名とパッケージ名から対応するヘルプドキュメント (Rd
オブジェクト) を取得する関数, display_help_section()
はその Rd
オブジェクトから任意のセクションを取り出す関数, detect_Rd_text()
は複数の Rd
内の検索を簡単にするための関数である
require(tidyverse) require(rvest) require(shiny) make_help_Rd <- function(topic, package){ topic <- str_split(topic, " ", simplify = T)[, 1] # Item には name (Title) のような書き方もある file <- utils:::index.search(topic, paths = find.package(package)) path <- dirname(file) RdDB <- file.path(path, package) tools:::fetchRdDB(RdDB, basename(file)) } display_help_section <- function(Rd, section = "Format"){ txt <- capture.output({tools::Rd2HTML(Rd)}) %>% paste(collapse = "\n") %>% read_html %>% html_nodes(xpath=paste0("//h3[contains(text(), '", section, "')]/following::p")) %>% as.character %>% paste(collapse = "\n") %>% htmltools::HTML('<html><head><meta charset="utf-8"/></head>', ., "</html>") #%>% view_html <- function(html) { shiny::shinyApp( ui = htmltools::HTML(html), server = function(input, output) {} ) } view_html(txt) } detect_Rd_text <- function(x, pattern, negate = F){ capture.output({tools::Rd2txt(x)}) %>% paste(collapse = "\n") %>% str_detect(pattern, negate) }
例えば以下のように使う.
(1) ヘルプドキュメントを全取得
as_tibble(data()$results) %>% mutate(Rd = map2(Item, Package, ~make_help_Rd(.x, .y)))
# A tibble: 139 x 5 Package LibPath Item Title Rd <chr> <chr> <chr> <chr> <lis> 1 forcats /home/ill/R/x86_64-pc-linux-gnu-library/3.6 gss_cat A sample of categorical variables from the General Social sur… <Rd> 2 stringr /home/ill/R/x86_64-pc-linux-gnu-library/3.6 fruit Sample character vectors for practicing string manipulations. <Rd> 3 stringr /home/ill/R/x86_64-pc-linux-gnu-library/3.6 sentences Sample character vectors for practicing string manipulations. <Rd> 4 stringr /home/ill/R/x86_64-pc-linux-gnu-library/3.6 words Sample character vectors for practicing string manipulations. <Rd> 5 dplyr /home/ill/R/x86_64-pc-linux-gnu-library/3.6 band_instruments Band membership <Rd> 6 dplyr /home/ill/R/x86_64-pc-linux-gnu-library/3.6 band_instruments2 Band membership <Rd> 7 dplyr /home/ill/R/x86_64-pc-linux-gnu-library/3.6 band_members Band membership <Rd> 8 dplyr /home/ill/R/x86_64-pc-linux-gnu-library/3.6 starwars Starwars characters <Rd> 9 dplyr /home/ill/R/x86_64-pc-linux-gnu-library/3.6 storms Storm tracks data <Rd> 10 tidyr /home/ill/R/x86_64-pc-linux-gnu-library/3.6 billboard Song rankings for billboard top 100 in the year 2000 <Rd> # … with 129 more rows
(2) Rd
内をキーワード検索してマッチしたものだけ取り出す. 例えば iris
という文字列が含まれるのは
as_tibble(data()$results) %>% mutate(Rd = map2(Item, Package, ~make_help_Rd(.x, .y))) %>% filter(map_lgl(Rd, ~detect_Rd_text(.x, "iris")))
# A tibble: 2 x 5 Package LibPath Item Title Rd <chr> <chr> <chr> <chr> <list> 1 datasets /usr/lib/R/library iris Edgar Anderson's Iris Data <Rd> 2 datasets /usr/lib/R/library iris3 Edgar Anderson's Iris Data <Rd>
(3) 1行目のRd
のFormat 部分を表示
as_tibble(data()$results)[1, ] %>% mutate(Rd = map2(Item, Package, ~make_help_Rd(.x, .y))) %>% .$Rd %>% .[[1]] %>% display_help_section()
year of survey, 2000–2014 age. Maximum age truncated to 89. marital status race reported income party affiliation religion denomination hours per day watching tv Downloaded from https://gssdataexplorer.norc.org/.
技術的な解説
例えば以下の stackoverflow の質問にもあるように, 本来なら help()
だけでドキュメントオブジェクトを取得できる.
How do I store the html or text of a R helpfile into a variable - Stack Overflow
しかし NSE が邪魔しているのか mutate()
内でうまく動作しなかった. 原因特定が大変そうだったので, help()
のソースを確認し, utils:::.getHelpFile()
などを参考に mutate()
内部でも動作する関数を自作した.
さらに, 組み込みパッケージの tools
には Rd
オブジェクトをプレーンテキストや HTML に変換する関数が用意されているので, 一旦 HTML に変換してから rvest
を通して必要な部分だけを取り出すようにした.
このHTML形式のヘルプドキュメントを表示させたいのだが, 普段あまりそういう使い方をしないのでどうするのが最もシンプルなやり方なのかなかなか思いつかなかった. すぐに思いつくのは shiny を使うことだが, ちょっとHTMLをレンダリングするだけで持ち出すのも大げさな気がしていろいろ模索していた. R-wakalang の方でも質問したが, 結局 shiny
が一番簡単そうだった.
結論
というわけでRデータ・セットのヘルプドキュメントを一括で取得する方法がわかった. しかしヘルプを取り出して表示するのに shiny
を使うのは物々しすぎる気がする.
ドキュメントが少ないのでなんかあんまりおもしろくない割に時間がかかってしまった. というかデータセットのヘルプ取得以外に応用の余地がありそうな話である気がする. 例えば References を一括取得するとか.