Rで鶴亀算を解いてみる
工学や経済学の教育を受けてない人(例:筆者)は線形代数を使って現実の問題を解く機会に恵まれない。若くない人(例:筆者)は教科書を開いてみる前にまず自分が何を学ぶのかを知りたがる。ともかく誰でも知っている2行2列の最単純のケースでやってみよう。
Rで鶴亀算を解いてみる。
鶴と亀を混合し、頓着せずに数えると頭が3個、足が10本。
関数cは要素からベクトルの生成。関数rbindはベクトルを行ベクトルとして行列を生成。
> b = c(3,10) ; b [1] 3 10 > head = c(1,1) > feet = c(2,4) > m = rbind(head,feet); m [,1] [,2] head 1 1 feet 2 4 > solve(m, b) [1] 1 2
鶴が1羽、亀が2匹。内部的には消去法を使っているのだろうか?
(追記)R 2.14.0のsolve.Rを読むと通常はLAPACKのLA_GESVを呼び出す。LAPACKでの実装はLU分解によるGauss消去法。ただしRのsolveからはpivot選択の結果は取れない
わざわざ反復法を使って解いてみる。まずJacobi法。
係数行列mを対角要素dとそれ以外rに分け、dの逆行列を求めて式にぶちこみ、回す。2x2行列では全くの無駄。行列やベクトルの掛け算を %*% と書くのが戸惑う。
> b = c(3,10) ; b [1] 3 10 > d_1 = c(1,0) > d_2 = c(0,4) > r_1 = c(0,1) > r_2 = c(2,0) > d = rbind(d_1,d_2); d d [,1] [,2] d_1 1 0 d_2 0 4 > r = rbind(r_1,r_2); r [,1] [,2] r_1 0 1 r_2 2 0 > d_inv = solve(d); d_inv d_1 d_2 [1,] 1 0.00 [2,] 0 0.25 > i = c(0,0) > x_ = i > x = d_inv %*% (b - r %*% x_) ; x_ = x ; x [,1] [1,] 3.0 [2,] 2.5 > x = d_inv %*% (b - r %*% x_) ; x_ = x ; x [,1] [1,] 0.5 [2,] 1.0 [1,] 2.00 [2,] 2.25 [1,] 0.75 [2,] 1.50 [1,] 1.500 [2,] 2.125 [1,] 0.875 [2,] 1.750 [1,] 1.2500 [2,] 2.0625 [1,] 0.9375 [2,] 1.8750 [1,] 1.12500 [2,] 2.03125 [1,] 0.96875 [2,] 1.93750 [1,] 1.062500 [2,] 2.015625 [1,] 0.984375 [2,] 1.968750 [1,] 1.031250 [2,] 2.007812 [1,] 0.9921875 [2,] 1.9843750 [1,] 1.015625 [2,] 2.003906 [1,] 0.9960938 [2,] 1.9921875 [1,] 1.007812 [2,] 2.001953 [1,] 0.9980469 [2,] 1.9960938 [1,] 1.003906 [2,] 2.000977 [1,] 0.9990234 [2,] 1.9980469
初期値(0,0)からの反復計算は、最初の結果(1,2)に収束していっている。
今度はGauss-Seidel法。
計算を要素毎にやって、計算の済んだ要素を別の要素の計算ですぐ使う点がJacobi法と違うところで、だから式としては行列の掛け算ではなくて、それぞれの要素の式になる。
Jacobiの時と明らかに収束の仕方が違うのだが、自分にはまだこの原因がわかってない。
(追記)逐次代入で一個前の値は本当は要らないし = は <- と書くのがRとしては正統派らしい
> b = c(3,10) ; b [1] 3 10 > x_ = 0 ; y_ = 0 > x = 3 - y_ ; x_ = x ; y = .25 * (10 - 2 * x_) ; y_ = y ; c(x,y) [1] 3 1 > x = 3 - y_ ; x_ = x ; y = .25 * (10 - 2 * x_) ; y_ = y ; c(x,y) [1] 2.0 1.5 > x = 3 - y_ ; x_ = x ; y = .25 * (10 - 2 * x_) ; y_ = y ; c(x,y) [1] 1.50 1.75 > x = 3 - y_ ; x_ = x ; y = .25 * (10 - 2 * x_) ; y_ = y ; c(x,y) [1] 1.250 1.875 > x = 3 - y_ ; x_ = x ; y = .25 * (10 - 2 * x_) ; y_ = y ; c(x,y) [1] 1.1250 1.9375 > x = 3 - y_ ; x_ = x ; y = .25 * (10 - 2 * x_) ; y_ = y ; c(x,y) [1] 1.06250 1.96875 > x = 3 - y_ ; x_ = x ; y = .25 * (10 - 2 * x_) ; y_ = y ; c(x,y) [1] 1.031250 1.984375 > x = 3 - y_ ; x_ = x ; y = .25 * (10 - 2 * x_) ; y_ = y ; c(x,y) [1] 1.015625 1.992188 > x = 3 - y_ ; x_ = x ; y = .25 * (10 - 2 * x_) ; y_ = y ; c(x,y) [1] 1.007812 1.996094 > x = 3 - y_ ; x_ = x ; y = .25 * (10 - 2 * x_) ; y_ = y ; c(x,y) [1] 1.003906 1.998047 > x = 3 - y_ ; x_ = x ; y = .25 * (10 - 2 * x_) ; y_ = y ; c(x,y) [1] 1.001953 1.999023 > x = 3 - y_ ; x_ = x ; y = .25 * (10 - 2 * x_) ; y_ = y ; c(x,y) [1] 1.000977 1.999512 > x = 3 - y_ ; x_ = x ; y = .25 * (10 - 2 * x_) ; y_ = y ; c(x,y) [1] 1.000488 1.999756 > x = 3 - y_ ; x_ = x ; y = .25 * (10 - 2 * x_) ; y_ = y ; c(x,y) [1] 1.000244 1.999878
行列式を使う解法(Cramer's rule)
係数行列mと頭足ベクトルbは前と同じ。bでmの列を置き換え行列式を求め、係数行列の行列式det(m)で割る。
b は c(3,10) としても rbind(3,10) としても結果は変わらない。Rのベクトル(前者)は縦横の区別がなく、文脈によって適切に転置(キャスト)されるが、後者は2行1列の行列ということになり、これは自動で転置できない。なお当然ながら t(cbind(3,10)) としても同じ結果になる。
> b = c(3,10) ; b [1] 3 10 > m = rbind(c(1,1),c(2,4)) ; m [,1] [,2] [1,] 1 1 [2,] 2 4 > det(m) [1] 2 > m_1 = cbind(b,c(1,4)) ; m_1 b [1,] 3 1 [2,] 10 4 > det(m_1) [1] 2 > m_2 = cbind(c(1,2), b) ; m_2 b [1,] 1 3 [2,] 2 10 > det(m_2) [1] 4 > c(det(m_1) / det(m), det(m_2) / det(m)) [1] 1 2
自分のためのおまけ
- ls(); で定義済みオブジェクトの一覧(実体はobjects関数と同じっぽい)
- rm(object); で特定のオブジェクト削除
- 某設定ファイルのパーザ書こう。。
- 固有値とか
> m [,1] [,2] [1,] 1 1 [2,] 2 4 > eigen(m) $values [1] 4.5615528 0.4384472 $vectors [,1] [,2] [1,] -0.2703230 -0.8719282 [2,] -0.9627697 0.4896337 > a = eigen(m)$vectors[,1] > m %*% a [,1] [1,] -1.233093 [2,] -4.391725 > eigen(m)$values[1] * eigen(m)$vectors[,1] [1] -1.233093 -4.391725 > dim(m) [1] 2 2 > rank(m) [1] 1.5 3.0 1.5 4.0 > rownames(m) = c("うえ", "した") > m [,1] [,2] うえ 1 1 した 2 4 > colnames(m) = c("みぎ", "ひだり") > m みぎ ひだり うえ 1 1 した 2 4 > "これ" [1] "これ" > c("これ") [1] "これ" > m みぎ ひだり うえ 1 1 した 2 4 > m[1,1] = 5 > m みぎ ひだり うえ 5 1 した 2 4 > m[1,1] [1] 5 > m[2,2] [1] 4 > m[1] [1] 5 > m[4] [1] 4 > length(m) [1] 4 > t <- matrix(c(1,5,3,7),ncol=2,byrow=TRUE) > t [,1] [,2] [1,] 1 5 [2,] 3 7 > class(t) [1] "matrix" > t <- as.table(t) > class(t) [1] "table" > t A B A 1 5 B 3 7 > attributes(t) $dim [1] 2 2 $dimnames $dimnames[[1]] [1] "A" "B" $dimnames[[2]] [1] "A" "B" $class [1] "table"