データサイエンスブームもひと段落しつつあるこの頃であるが、統計解析や機械学習を行なうために、どのプログラミング言語を学習すべきかと言う質問はずっと頻出の質問だ。候補や推奨を見るとPython、R、Matlab、Juliaあたりが人気の候補だが、なぜかRは学習困難な言語と言う話がされることがあり*1、醜悪と言っている人もいる。しかし、人気のプログラミング言語の中ではシンプルな文法を持っているのがRなので、これは違和感のある主張だ。
1. Rの文法はとても簡素
他のプログラミング言語にそこそこ習熟*2してからRの文法を学ぶと、あれも無い、これも無いと、潔さに感服する。
- 変数が値渡しのみ
- C/C++で言うポインターや、PythonやJuliaにある参照渡しと値渡しの違い*3に悩む必要がない。
- 動的型付けのみ
- あらかじめ型宣言する必要がない。
- 変数にならないオブジェクトが無い
- 関数や環境(namespace)すら変数として数字や文字と同様に取り扱える*4。学習コストが低いだけではなく、これであらゆるオブジェクトの保存と読み込みが標準で簡単にできる。PythonのpickleやJuliaのFileIO/JLD2では関数の保存に制約がかかったりするが、そういう縛りはない。整形データや計算結果を保存してから、次の作業に入るようなことも容易だ。
- 無名関数(ラムダ式)しかない
- 他のプログラミング言語でラムダ式が導入されて便利さが話題になる15年間であったが、30年前の1992年の誕生時点から無名関数しかなかった。
- Pythonのデコレータ、Juliaのマクロにあたる命令がない
- 引数の計算/実行をしてから関数を呼ぶ言語だと、引数の計算/実行を後に回せる関数に似た機能が必要になるが、Rは遅延実行なので関数で間に合うというか、すべてマクロ的なことになっている。同様に、引数の式の前の処理をはさむことも容易なので、デコレータ的なことも容易にできる。
- 複合データ構造はリストとデータフレームしかない
- データ分析ではさほど役立たない*5複雑な継承やインスタンス生成のクラスを書くGoFデザインパターンによるオブジェクト指向プログラミングをしなくて良いし、Juliaのように変更不可構造体と変更可能構造体のような区分けも考慮しなくてよい。Python(or Julia)のように、リスト(or 辞書)とタプルの使い分けもない。
- リストにnames, class, row.names属性をつけるとデータフレームになったりするので、リストとデータフレームの違いもさほど無い。環境はリストとは別モノだが、名前空間をつくるためのものだし、データ構造としてはリストと同様である。
- スカラーとベクター(配列)の区分けが無い
- スカラーは長さ1のベクターなので、スカラーとベクターで処理を変える必要が多くない。ベクターに対応したコードを書きたくなり、コードの汎用性が増す。
- 属性(attribute)と言うプロパティの状態で識別しているだけなので、ベクターと行列(matrix)と因子(factor)の違いもあまりない*6。
- データ型の種類が最低限
- C89のように型が足りないという事はなく、数値や文字列といった型はあるが、Juliaのように抽象型を継承した多種多様な具象型があって、意識してコーディングしないといけない事も無い。整数はSigned/Unsignedで8/16/32/64/128かを気にせずintegerだと考えれば良いし、浮動小数点はFloat 16/32/64を考えずにnumericだと考えれば良い*7。
- 変数スコープのグローバル領域が例外的ではない
- グローバル変数の更新が遅いとか、親スコープの変数であることを指定するnonlocal宣言でグローバル領域の変数を更新できないとか、例外的なことが無い。
これらの簡素な文法がメモリー消費量の大きさと、(Cで書かれた関数に任せないループ処理が多いときの)実行速度の遅さにつながっているわけだが、複雑怪奇と言うことはない。
行列型やデータフレームや因子型*8は複雑とも言えるが、統計解析にはぜひ欲しい機能であり、Pythonでデータ解析をするときに使うNumPy/ScipyとPandasのパッケージでも採用されている。PythonやJuliaに無い文法上の特徴と言えば
- names(変数)<-名前; の命令文で、ベクトルの添字ごと、行列の行や列ごとに名前をふれるようなところ
- 変数の長さが違っても、代入される方が代入する方の自然数倍の長さの場合は、代入する方を繰り返して伸張して代入する
ぐらいだ。ビルトインされている関数が多めではあるが、Python、Matlab、Juliaあたりで統計解析をしようと思ったときに使うモジュール/パッケージ群と比較して多いと言うわけではない。
2. Rの開発環境はお手軽に整う
RStudioと言う定番の統合開発環境の完成度が高いし*10、メモ帳でコードを書いていく場合でも標準内蔵デバッキング関数が扱いやすい。
統合開発環境を含むデバッガーで行番号や関数名を指定せずに、ソースコードの任意の場所にbrowser()と書いておくだけで、そこでデバッグモードに入れるプログラミング言語は他に思いつかない。
ライブラリを探すのが困難と言うこともなく、Perl/CPANから一般化していったネットワーク経由のパッケージ管理システムCRANもあるし、統計解析に限れば登録されているパッケージは最も豊富だ。PythonやJuliaにもあるので強みではないが、ライブラリがどこにあるのか分からず学習が困難になったりはしない。
プロット時の日本語フォント設定が躓きポイントだが機械的に解消できる*9し、ここはどのオープンソースのプログラミング言語を使っても問題になりがちな点である。
3. Rは使い込むのも簡単
Rは高速でシステム寄りの操作が得意なコンパイラ言語との連携がしやすいプログラミング言語である。RのC拡張は、C関数呼び出し(c-call)ではなくてC拡張(c-extension)だけに、Rの内部関数が出来ることは全てできるCによる関数を書くことができる。他のプログラミング言語だと、Cとの連携がそこまで容易ではないこともある。また、Rcppを使えば行列演算ができるようになったC++で拡張を拍子抜けするぐらい気楽に書けるし、今でも数値解析最速と考えられるFortranのモジュールも呼びだせる*11。
4. Rが習得困難だと思われてしまう理由
Rの文法はとても簡素だし、開発環境はお手軽に整うし、ウェブに大量の資料があるし、内蔵のヘルプも充実している。かなり学習に時間をかけないと習熟できないと言うような話には根拠が無い。しかし、Rの学習が難しいプログラミング言語だと言われるのには、恐らく理由がある。
それはRがどこでどのように教えられているかだ。多くの場合、Rと同時に統計学を教えるので、統計学の難しさが仇になって、Rの理解に注力できないのではないかと言う指摘がされている*12。確かに易しいとされるPythonの入門チュートリアルでは統計学を教えない。
逆に考えれば、1日ぐらいかけてRの文法を先に学習しておくと、Rを相対的に難しく感じなくなる可能性がある。Rで躓いている人は、統計解析に入る前に、文法の説明用の例を打ち込んで実行していくトレーニングを試して見てほしい。
*1"Unlike Python, R is a complicated language and is difficult for a beginner to learn."
*2Javaであればリフレクション周りに詳しいぐらいで。
*3値渡しか参照渡しを意識していないと、変数の値をコピーして変更したつもりだったのに、コピー元の値も変更されてしまうような事が起きる(引数は参照渡し(代入で困った人はこちら) - MATLAB移民のためのJulia tips)。
*4C言語などでは変数に入れられるのは関数のポインターであって、関数自体ではない。
*5数値解析でももちろん有益な単体テストはRでもできる(Rで単体テスト - あらびき日記)。
*6Rのオブジェクトのattributes(属性)についてのメモ - Qiita(注意:統計解析をするだけならば、存在を気にしなくて済むと思われる)
*7singleもあってFortranやCとのやり取りで使うこともがるが、Rの関数はnumericでできている。
*8因子型はさほど有り難味を感じないので理解が進まないが、ペタペタと例を貼り付けるとすぐに理解できる(【R】factor型について(1)_Levels:・・・って? - 一所懸命に手抜きする)。しかし、都道府県のようにコードと名前の両方があったりするので、名前だけでコード順に並び替えたりしないので、モデル式でダミー変数を指定するためだけの('-' )\(--;)BAKI
*9使い始めた頃はノウハウが錯綜していたのだが、今はill-defined氏が簡単な対処方法まとめてくれている(おまえはもうRのグラフの日本語表示に悩まない (各OS対応) - ill-identified diary)。私はwindowsFonts(Meiryo = windowsFont("Meiryo")); par(family="Meiryo")とべたべた書いていたりするが('-' )\(--;)BAKI
*10私はVS Code/R Extensionや単なるテキスト・エディタで書いていることが多い('-' )\(--;)BAKI
0 コメント:
コメントを投稿