普通の
プログラミング言語 R(仮)
  2010/5/9 id:n_shuyo / @shuyo
   中谷 秀洋@サイボウズ・ラボ
最近
機械学習
いろいろ
実装してみたくて
R始めました
そんなわけで
R歴
まもなく1年
Rって
便利ですね!
これが
E-step:
                                           2
            1 (k = argminj     n − j       のとき)
    rnk =
                      0 (それ以外)
M-step:
                          n rnk n
                  k =
                           n rnk


  K-means クラスタリングの更新式
Rなら1行
mu<-t(sapply(1:K,function
(k)colMeans(x[max.col(
-sapply(1:K,function(i)
colSums((t(x)-mu[i,])^2)))
==k,])));
Rって
ほんと便利!!
でも……
Rって……
変ですよね?
すごいことが
簡単にできるけど
簡単なことが
やたら難しかったり
予想と違う動きで
  ハマったり
いままで結構いろんな言語を
   触ってきたつもりだけれど──

Ruby MSX-BASICX-BASIC
COBOL   C++   Perl ぺけBASI
                           javascript
ActionScript R
       PHP Excel VBA
    C                               XSLT

          Erlang                PL/SQL
 JavaZ80       Brainf*ck
                  6502/680x
                            Visual BASIC
                                   x86
                       MS-BASIC
気持ち悪い
と思った言語は
  R だけ
Rの一番良いところは
 統計学者が
 作っているところだ。
Rの一番悪いところは
 統計学者が
 作っているところだ。
          [要出典]
[出典]
でも R だって
普通の
プログラミング言語に
  なりたいはず!
そのためには
「普通のプログラミング言語」
       の
 「普通のプログラミング」
  ができるようになれば!
もちろん
メタプログラミング
 のことですね!
Rで普通の
メタプログラミング
  2010/5/9 id:n_shuyo
R って意外と
インスペクトと
 動的定義が
得意なんですよ!
というわけで
クイズです
次の文を実行したとき、
f は何になるでしょう?

f <- function(x){x*2};
関数?
正解は「クロージャ」

> f <- function(x){x*2}
> typeof(f)
[1] "closure"
「クロージャ」って
なんかあの
難しいやつ
Wikipedia「クロージャ」
クロージャ(クロージャー、closure、閉
包)はプログラミング言語における関
数の一種。引数以外の変数を実行時
の環境ではなく、自身が定義された環
境(静的スコープ)において解決する
ことを特徴とする。関数とそれを評価
する環境のペアであるともいえる。
「関数と
それを評価する
 環境のペア」
たしかにクロージャ
> f <- function(x){ x*2 };
> body(f)        # 関数本体
{
    x * 2
}
> environment(f) # 環境
<environment: R_GlobalEnv>
グローバル環境
グローバル環境はワークスペースの
  ルートをなす
.GlobalEnv がエイリアス
> environment(f)
<environment: R_GlobalEnv>
> .GlobalEnv
<environment: R_GlobalEnv>
環境の中身を見る
ls.str(環境) もしくは as.list(環境)で
  見ることが出来る
> a <- 1
> ls.str(.GlobalEnv)
a : num 1
f : function(x)
> as.list(.GlobalEnv)
$a
[1] 1
$f
function(x){x*2}
関数は子環境を作る
> f <- function(x) {
+ print(environment());
+ print(parent.env(environment()));
+ print(as.list(environment()));
+ }
> f(3)
<environment: 0x064bd8f0> # 子環境
<environment: R_GlobalEnv> # 親環境
$x     # 子環境の中身
[1] 3 # ←3が出る仕組みは別の長い話
子環境は毎回作られる
関数は呼び出されるごとに子環境を
 作成する(スコープの話はしません)
> f <- function() {
+ print(environment());
+ }
> f()
<environment: 0x06dbdd54> # 子環境1
> f()
<environment: 0x06ca9c28> # 子環境2
クロージャは環境とひもづく
定義されたときの環境を「閉包」
> f <- function() {
+   print(environment());
+   function() {}
+ }
> g <- f()
<environment: 0x061d5cb4> # f の子環境
> environment(g)          #   ||
<environment: 0x061d5cb4> # g の環境
クロージャの環境の中身
> f <- function() {
+ x <- 3
+ function(a){ a * x } # 環境を閉包
+ }
> g <- f()
> g
function(a){ a * x }      # x って何?
<environment: 0x06dbe0b8> # この中を見れば…
> ls.str(environment(g))
x : num 3 # g の環境では x <- 3
> g(2)
[1] 6 # つまり g は値を3倍する関数
準備完了
クロージャを
いじってみよう!
クロージャの環境は
   外からいじれる
> as.list(environment(g))
$x
[1] 3
> environment(g)$x <- 4 # 書き換え!
> ls.str(environment(g))
x : num 4
> g(2)
[1] 8   # 値を4倍する関数に変わった!
環境のまるごと差し替え
new.env() で新しい環境を作成し、
 クロージャの環境に差し替える
> e <- new.env()      # 環境の作成
> e$x <- 5            # 値をセット
> environment(g) <- e # 差し替え
> ls.str(environment(g)) # 環境を確認
x : num 5
> g(3)
[1] 15 # 値を5倍する関数に!
関数本体も差し替え!
> g
function(a){ a * x }    # 掛け算する関数
<environment: 0x06dbe0b8>
> body(g) <- expression({ a + x })
> g
function (a)
{
    a + x       # 足し算する関数になった!
}
<environment: 0x06dbe0b8>
> g(1)
[1] 6           # 5を足す関数に変わった
引数だっていじれる!
> formals(g)
$a # 引数 a を持つ。デフォルト値なし

> formals(g)$a <- 2
> formals(g)
$a
[1] 2 # 引数 a のデフォルト値が 2 に

> g()
[1] 7   # 2 + 5
結論
Rかわいいよ!
え?
「それが
なんの役に
立つの?」
……
……えーと、
こんな感じで
「R の中身」が
わかってくると
R で「できること」と
 「できないこと」が
わかるように
なるかもね!(棒読み)
ま、
役に立つか
 なんて
一番つまんない
尺度ですよね!
[没ネタ集]
「Rで変なコードを書こう!」とか
 遅延評価ってわかりにくいよね。
> a
[1] 0
> g <- f(a<-3) # f は「とある関数」
> a
[1] 0    # a は 0 のまま
> g()    # でも g() を呼ぶと……
> a
[1] 3    # 3 に変わる
「なんでエラーなの?」とか
 なぜか plot できない!
 しかもエラーメッセージが意味不明
 (わかる人にはわかるけど、
  わかる人はこんなコード書かない)
> plot(function(x) x+x^2);    # 問題なし
> f <- function(x) c(x,x^2);
> plot(function(x) sum(f(x)))
以下にエラー xy.coords(x, y, xlabel, ylabel, log) :
 'x' and 'y' lengths differ   # 何このエラー?
「なんでエラーじゃないの?」とか
「なんでそんな書き方出来るの?
 文法どうなってんの?」って
 思うことありません?
> f(abc) # f は「よくある関数」
以下にエラー f(abc) :
  オブジェクト 'abc' がありません

> g(abc)   # g は「とある関数」
> # あれ?    エラーにならない……
「あるある~」小ネタとか
plot() の重ね描きで、同じ引数を何
 度も書かなくて済む方法ないの?
plot(data1,
  xlim=c(-5,5), ylim=c(-5,5), ann=F);
par(new=T);
plot(data2,
  xlim=c(-5,5), ylim=c(-5,5), ann=F);
par(new=T);
plot(data3,
  xlim=c(-5,5), ylim=c(-5,5), ann=F);
などなど
ほかにも
いろいろ
なくもなかったん
  ですけど
時間ないので
またの機会(あるかな?)
ありがとう
ございました。

普通のプログラミング言語R