普通のプログラミング言語r
DESCRIPTION
Tsukuba.R #7TRANSCRIPT
普通のプログラミング言語 R(仮)
2010/5/9 id:n_shuyo / @shuyo
中谷 秀洋@サイボウズ・ラボ
最近
機械学習
いろいろ実装してみたくて
R始めました
そんなわけで
R歴
まもなく1年
Rって便利ですね!
K-means クラスタリングの更新式
これがE-step:
rnk = 1 (k = argminj 𝐱n − 𝛍j
2のとき)
0 (それ以外)
M-step:
𝛍k = rnk 𝐱nn
rnkn
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って……
変ですよね?
すごいことが簡単にできるけど
簡単なことがやたら難しかったり
予想と違う動きでハマったり
ぺけBASIC
Excel VBA
MSX-BASIC
Visual BASIC
MC68000
PHP
いままで結構いろんな言語を触ってきたつもりだけれど──
MS-BASICZ80
RErlang
C++C
Ruby
Brainf*ck
X-BASIC
Java
javascriptActionScript
Python
XSLT
PL/SQL
COBOL Perl
6502/680x x86
気持ち悪いと思った言語は
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"
「クロージャ」って
なんかあの難しいやつ
クロージャ(クロージャー、closure、閉包)はプログラミング言語における関数の一種。引数以外の変数を実行時の環境ではなく、自身が定義された環境(静的スコープ)において解決することを特徴とする。関数とそれを評価する環境のペアであるともいえる。
Wikipedia「クロージャ」
「関数とそれを評価する環境のペア」
たしかにクロージャ
> 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 1f : function(x)> as.list(.GlobalEnv)$a[1] 1$ffunction(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()> gfunction(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倍する関数に!
関数本体も差し替え!> gfunction(a){ a * x } # 掛け算する関数<environment: 0x06dbe0b8>> body(g) <- expression({ a + x })> gfunction (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);
などなど
ほかにも
いろいろ
なくもなかったんですけど
時間ないのでまたの機会(あるかな?)
ありがとうございました。