ggplot2でなんでもプロット(table編) #RAdventJP
R Advent Calendar 2013の2日目です。
今回のネタは、本当は去年どっかでやろうと思ってたものだったんですが、機を逃して温めすぎて発酵しかけてたものです(このネタの存在自体忘れてた)。とりあえず、日本語での情報は少なくともまだウェブには無いようなので安心。ちなみにtable編と書いていますが、続編の予定はありません。もちろん、興味を持っていただいた方は好きに引き継いでもらってかまいません。
fortifyとは?
さて、ggplot2を利用されている方は多いと思いますが、高機能な分みなさん使いこなすのに苦労されているようです。実際一朝一夕で使えるようにはならないものではあるんですが、実際には便利な機能があるのにそれを知らないために苦労してただけ、ということもあったりします。今回紹介するのは、そんな便利機能の中でも特に知名度が低いと思われるfortify()という機能(関数)です。
R5クラスの継承の罠
あ...ありのまま 今 起こった事を(ry
R5クラスでサブクラスを定義すると、スーパークラスがインスタンス化されます。
な… 何を言っているのか(ry
本当に意味が分からないです。
setRefClass("Parent", methods=list( initialize = function()print("run"))) setRefClass("Child", contains = "Parent")
Parentクラスはインスタンス化されるさいに"run"と表示するだけのクラスです。ChildクラスはParentクラスを継承しているだけのクラスです。
> setRefClass("Parent",
+ methods=list(
+ initialize = function()print("run"))
+ )
> setRefClass("Child", contains = "Parent")
[1] "run"
[1] "run"実行するとこうなります。Childクラスのクラス定義を行っただけで、なぜかParentクラスが二回インスタンス化されました。
この挙動は、以下のようなクラス定義の場合に問題を引き起こします。
setRefClass("Parent", fields = c("x", "y"), methods = list( initialize = function(...) { initFields(...) y <<- x * 2 }) ) setRefClass("Child", contains = "Parent")
Parentクラスはインスタンス化されるさいにy <<- x * 2を実行します。なので、new("Parent", x=1)のように、インスタンス化のさいに引数でxの値を与えておかなければ、エラーになります。ChildクラスはあいかわらずParentクラスを継承しているだけのクラスです。
> setRefClass("Parent",
+ fields = c("x", "y"),
+ methods = list(
+ initialize = function(...) {
+ initFields(...)
+ y <<- x * 2
+ })
+ )
> setRefClass("Child", contains = "Parent")
以下にエラー x * 2 : 二項演算子の引数が数値ではありません Childクラスはクラス定義すら行えません。
対応策としては、引数に初期値を与えておく、引数が与えられていない場合は即return()するかなんらかの例外処理を行う、などがあると思います。つまり、引数が与えられていなくても問題が起きないようにする、ということです。
個人的に一番問題だと思うのは、パッケージでR5クラスを使う場合です。パッケージをバイナリにビルドするときやlibrary()で読み込むときには、パッケージ内のスクリプトがいちど全部実行されるのですが、このときスクリプトのファイルが読み込まれる順番は辞書順です*1。サブクラスの前にスーパークラスが定義されていなければならないというのは、まあスクリプト言語では普通だと思います。しかし、R5クラスの場合、スーパークラスのinitializeメソッド内で使われている関数やクラスが、サブクラスの定義よりも前に定義されている必要がある、という複雑な問題が起きてしまいます。上記の対応策を取っておけば回避はできますが、知らなければ謎のバグに苦しむことになります(なりました)。
この副作用、どこかの文書に載ってるんでしょうか…?
> sessionInfo() R version 3.0.0 (2013-04-03) Platform: x86_64-w64-mingw32/x64 (64-bit) locale: [1] LC_COLLATE=Japanese_Japan.932 LC_CTYPE=Japanese_Japan.932 [3] LC_MONETARY=Japanese_Japan.932 LC_NUMERIC=C [5] LC_TIME=Japanese_Japan.932 attached base packages: [1] stats graphics grDevices utils datasets methods [7] base loaded via a namespace (and not attached): [1] codetools_0.2-8 tools_3.0.0
*1:いろんなパッケージのソースを見てみると、a.Rとかzzz.Rという謎の名前のファイルがありますが、これはつまり最初に読み込んでほしいファイルと最後に読み込んでほしいファイルです。
GUI for read.table
【追記】そもそも起動しないバグを修正。ローカルで作ってた関数を移し忘れました…。
総制作時間6時間ぐらい?Gtk力の高まりを感じます。ぜんぜんテストしてないので、バグがあれば教えてください。バグというか、例外処理を入れてないのですぐエラー吐くと思いますが…それはご愛敬ということで。

上がクラス定義、下が実行用スクリプト。必要パッケージはRGtk2のみ。そのうちRzにも取り込みます。
しかし命名規則がひどすぎて恥ずかしい…。
第三回Japan.R入門セッション『はじめての「R」』補足 #rstatsj #JapanR
『はじめての「R」』やってきました!
第三回Japan.Rで入門セッションを担当させていただきました。
Japan.R当日の様子は@bob3bob3さんがまとめてくれています。
「第7回R研究集会(Rユーザー会)と第3回Japan.R #rjpusers #japanr」をトゥギャりました。 togetter.com/li/416482
— Bob#3さん (@bob3bob3) 12月 2, 2012で,入門セッションはというと,
50人くるはずが15人ぐらいしかいないw #JapanR
— 林真広/HAYASHI Masahiroさん (@phosphor_m) 12月 1, 2012こんな幕開けでしたが,最終的には30〜40人ぐらいのかたに来ていただいて無難に終えることができ,胸をなで下ろして午後の部を楽しんでいたのですが。
おや,slideshareにアップロードしたスライドに異変が…。
今日のスライド、昼に1300viewsぐらい行ってて、2000ぐらいいったかなーと思って今見たら4400…。いや、もっといい資料他にいっぱいありますから…。
— 林真広/HAYASHI Masahiroさん (@phosphor_m) 12月 1, 2012見たことのない数字が!
というか,viewsが7000超えって,ちょっと理解不能…。
— 林真広/HAYASHI Masahiroさん (@phosphor_m) 12月 1, 2012怖い!
そして現時点で約13000views,ついにはこんなメールまで届いてしまいました。

こんなにたくさんの人に見ていただけるなんて予想だにしておらず,作者冥利に尽きるのですが,全く実感が湧かないというのが正直なところです。Rの入門資料はいまやウェブにごろごろ転がっている中で,私のものが特別優れているということはないので,ここ最近でどれほどデータ解析需要が盛り上がったのかということがうかがえますね。
「つまずかないR入門」
以下駄文です。本題のスライド補足はもう少し下にありますので,お急ぎの方は飛ばしてください。
さて,内容についてなのですが,中にも書いているとおり,Rを使う上で重要な部分をかなり省略しています。なぜならば,「つまずかないR入門」を方針としたからです。これは,一度成功体験をしてもらい,「Rって思ってたより難しくないな」と感じてもらうことが大事だという考えに基づいています。
いままでにRの入門講習を何度もやっているのですが,終わったあとの感想で必ず出てくるのは,「やっぱりRって難しいけどがんばります!」というものです。これは,難しい部分をどんなに噛み砕いて説明しても,必ず出てくる感想でした。
そこで考えたのが,「そもそも入門講習のやり方が根本的に間違っているのではないか」ということでした。これまでは,Rの使う上で必要になる必要最小限の内容をできるだけ分かりやすく伝えよう,と考えてやってきました。しかし,にもかかわらず「難しい」という感想が出るということは,必要最小限であっても,そもそも1時間や2時間でそれら全てを教えることは不可能なのではないか,と。
なので,この資料を読んで,いざRを使ってみよう,と思っても,十中八九つまずくと思います。そもそも必要最小限にも達していない内容なのです。しかし,入門講習で最初の一歩からつまずくのと,一度成功体験をしてからつまずくのとでは,モチベーションの維持に大きく違いがあると考えています。入門講習でいきなりつまずいてしまえば,「Rは難しい」というイメージが定着してしまいますし,帰ってから自分でやりなおそうという気はなかなか起きないでしょう。
さて,講習会後の感想を聞いたり読んだりしたかぎりでは,この試みはなかなか成功しているのではないかと思います。しかし,不十分な内容の講習会を行って投げっぱなしでは,ちょっと無責任かな,という気もしてきました。また,講習会中に口頭で入れた補足は,ウェブでスライドだけ読んでいただいた方には伝わらないというのも気になります。ということで,スライドに足りない内容をここで少し補足しようと思います。
スライドの補足
データの読み込み
概要はこちらの資料で。
関数を使ったデータの読み込み
今回はRStudioのGUIを使ってCSVを読み込みましたが,当然Rにはデータを読み込むための関数が用意されています。CSVを読み込むread.csv,タブ区切りテキストを読み込むreade.delim,より柔軟にテキストファイルを読み込めるreade.tableが代表的です。
R-Source
パッケージを使えばExcelのファイルを直接読み込むこともできますが,メリットはほとんどありません。csvに変換して読み込むか,下のスライドで紹介されているクリップボードからの読み込みを使いましょう(105ページ以降です)*1。特に後者はとても便利な機能です。
作業ディレクトリ
データを読み込む前に,作業ディレクトリ*2を設定しておきましょう。作業ディレクトリを設定すると,そのディレクトリにあるファイルを読み書きすることが出来るようになります。作業ディレクトリの設定には,setwd関数を使うか,GUIで設定します。
R-Source
RStudioでは,メニューバーからSession>Set Working Directory>Choose Directoryで設定できます。
パス
パスについては,上のスライドを見てください。setwdで作業ディレクトリを設定する場合や,作業ディレクトリの中にないファイルを読み書きするためには,パスを使って場所を指定する必要があります。スライドにない注意点として,Windowsでは円マーク(¥)がバックスラッシュの代わりになります(というか同一のものになっています)。Macではoption+¥でバックスラッシュを入力できます。どちらにしろややこしいので,パスの区切りにはスラッシュを使うことをおすすめします。
文字コード
文字コードについても,上のスライドを見てください。基本的には,文字コードの変換はテキストエディタで行うことをおすすめします。テキストエディタでは文字コードの変換でエラーになることはほとんどありませんが(特定の文字が化けることはありますがその程度です),Rでは間違えるとエラーになってしまい,混乱してしまいがちです。
やむをえずread.csv等で文字コードを指定して読み込む場合は,fileEncodingオプションを使います(foreignパッケージのread.spssのみreencodeというオプションですが,使い方は同じです)。注意点として,Shift_JISのファイルを読み込むときは,Shift_JISではなくCP932を指定します*3。実例を書くと,read.csv("サンプル.csv", fileEncoding="CP932")となります。
尺度の水準
統計学における変数には,尺度の水準というものがあります。簡単な例を挙げると,あるクラスの身体計測の結果データがあったとします。そこには,性別,身長,体重といった変数があります。ここで,身長や体重のクラス平均を求めることはできます。しかし,性別のクラス平均というものを求めることはできるでしょうか?当然できませんね。性別のような変数をカテゴリ変数(または質的変数)と呼びます。このような考え方を厳密に進めた結果として,統計学では変数を下のリンク先にあるような4つのタイプに分類し,それを尺度の水準と定義しました。
データの水準
この尺度の水準は,Rを使う上でも密接に関わってきます。R上では,名義尺度をfactorクラス,順序尺度をorderedクラス,間隔尺度と比例尺度をnumericクラスで表現しており,厳密な使い分けが必要になっています。クラスについての説明は,続きを読んでください。
クラス
今回の講習会ではRにおけるクラスの概念を完全に省略しました。しかしこれを避けていては絶対にRを使えるようにはなりません。簡単な説明は下の資料の6ページに,もう少し詳しい説明は7ページ以降にあります。エラー頻出地帯でもあるので,気合いを入れて学習してください。
あとがき
ここまでで,やっと必要最小限にたどり着いたといえるでしょう。ここからは,自分がどのようにRを使うかを考え,自分にとって必要なものを学んでいく,という段階になります。自分なりの使い方を身につけ,楽しいRライフを送ってください!
Shinyで5分でできる株価チャートウェブアプリ
RにもWeb化の波が来てますね。
RStudio, IncがリリースしたShinyはRのみでサーバーも他言語も必要とせずウェブアプリを作成できる画期的なパッケージです。
Introducing Shiny: Easy web applications in R - rstudio.com/shiny/ #rstats #rstudio #shiny
— RStudioさん (@rstudioapp) 11月 8, 2012
概要はバタデ先生にお任せするとして,簡単なアプリを作ってみました。
ウェブアプリのスクリプトは,2つのファイルに分けて作成します。
1つめは,ui.Rという名前で作成します。
2つめは,server.Rという名前で作成します。
これらを1つのフォルダに保存します。ここではstockというフォルダを作って,そこに保存することにします。保存したら,Rを立ち上げ,stockのあるフォルダに作業環境を変更します。
まずはパッケージのインストール。
install.packages(c("RFinanceYJ", "quantmod"))
options(repos=c(RStudio="http://rstudio.org/_packages",
getOption("repos")))
install.packages("shiny")
あとは,起動するだけ!
library(shiny)
runApp("./stock")
ブラウザが立ち上がり,こんなページが表示されます。

銘柄コード,期間などを変更すると,リアルタイムでチャートが更新されます。簡単すぎてびっくりですね!ちなみに株式に関しては全く無知なので僕には聞かないでください。実データのほうがおもしろいかな,というだけの動機で株価チャートにしました。
Rz開発状況(プロット機能書き直し,ケースの選択等)
ぼちぼち開発してます。
現実逃避したくなったときに一気にやる感じなのであまり効率が良くないのですが。
ggplot2 0.9.2に対応させようとしていたはずが,いつの間にかプロット周辺をほぼ完全に書き直していたり。

プロット画面を切り離せるようになりました。インタラクティブにプロットを作り込む際に重宝します。UIもだいぶ整理しました。まだ汚いですが。

さらに,待望のスクリプト出力機能。これで,ggplot2学習用としても使えるようになりました。このためにかなりプログラムを書き直したので,機能追加も容易になりました。初心者向けにわかりやすくしつつ,ggplot2の表現力を最大限引き出せるようにしたいですね。今後は,themeまわりを拡充しようかと思っています。

あとは,ケースの選択機能をつけました。条件をsubsetに渡すだけなので,簡単にできました。このあたりのデータハンドリング機能は今後拡充予定です。まあ,気長に待ってください。
未実装な部分がちょこちょこあるので,CRANにはまだ上げられません。年内には,という感じです。
開発版は,githubおよびWindows用バイナリおよびソースを公開しているので,試してみてバグや要望を知らせていただけるととてもうれしいです。
Osaka.R休止します
趣味で始めた勉強会も,Rへの関心の高まりにともなってか,30人を超える人数が集まるようになり,順調といえば順調だったのですが。いろいろと思うところがあり,当面休止させていただきたいと思います。
深い理由があるわけではないのですが,不安定な生活や不定期のスケジュールの合間を縫って開催するのが,やや重荷になってきた,といったところです。現時点で首が回らなくなっているわけではないのですが,傷が深くなる前にどこを切るかと考えると,生活の中の優先順位で最下位にくるのはOsaka.Rだった,というだけの理由です。
本来知らない人とは会うのも話すのも嫌いかつ何事に対しても意欲のない意識の低い人間にもかかわらず,よく第7回まで続けられたな,というのが個人的な感想です。知らない人と話すのが大好きな意識の高い人間だったら,何も負担に感じずに続けていけたのだろうと思いますが。本来イベント事とは無縁の,教室の隅でなるべく存在感を薄くして本読んでるような人間です。
できれば後継者を見つけて引き継ぎたかったのですが…。というか今からでも誰か引き継いでいただけるとありがたいです。サイトの管理権限等お譲りいたします。