Rubyでm * n行列をかっこよく作って足してみた
こんばんは。
火曜日は1,2限に「パターン認識学」の講義があって、今日は2とか9とかのこんな感じのパターンを学習させて未知のパターンの数字を認識させる、みたいな講義でした。
やることは簡単で、まずこの5つの9のデータ白が0、黒が1だとしてそれを5*5行列として読み込んでそいつのセルごとの総和をプロトタイプ(5*5)として、未知の数値を判断してみよーって感じでした。
このデータの表現方法は自由だったので、僕は左上の9を
01110 01001 01111 00001 00011 (実際にスペースはないけど見やすそうなので)
といった感じに左上から右下に順に走査していく感じで表現して、この文字列をプログラム内で行列化してやろー的な目論見でこれが最初のコード。
def matrix(str) mat = Array.new(5,0).map{Array.new(5,0)} i = 0 while str[i] for j in 0...5 for k in 0...5 mat[j][k] = str[i] end end i+=1 end end
みたいな感じで冗長すぎてruby使う意味が一切感じられないクソみたいなコードでした。。これはあまりにもかっこ悪いってことでStringクラスとかもう一回復習してみて、かなり改善したのがこれ。
def matrix(str,m,n) exit unless str.size == m*n return str.split("").map(&:to_i).each_slice(m).to_a end
しかもm*n行列に対応できました。ただ、サイズがm*nじゃなかったら帰れ!ってことにして勝手に入力が整数文字列に限定していますが、整数文字列を1文字ずつsplit("")で分解して、それぞれをto_iで整数にします。この時点では
[1,2,3,4,5,6,7,8,9]
こんな感じのただの整数配列。こいつをm文字でスライスして配列に変換してやると1行でいい感じになりました!
試しに最初の9のデータを入れてやると
str = "0111001001011110000100011" p str.split("").map(&:to_i).each_slice(5).to_a #=>[[0, 1, 1, 1, 0], [0, 1, 0, 0, 1], [0, 1, 1, 1, 1], [0, 0, 0, 0, 1], [0, 0, 0, 1, 1]]
と一発で5*5行列に変換してくれました。
あとそのm*n行列同士の和を計算したかったので、これはどっかのサイトさんのコメントを参考(ほぼパクリ?)にして
def sum(mat1,mat2) return [mat1.flatten,mat2.flatten].transpose.map{|a| a.inject(:+)}.each_slice(m).to_a end
この1行で行列の加算が完了しました。
x = [[0, 0, 1, 1, 1], [0, 1, 0, 0, 1], [1, 1, 1, 1, 1], [0, 0, 0, 1, 1], [0, 0, 0, 1, 0]] y = [[0, 1, 1, 1, 0], [0, 1, 0, 0, 1], [0, 1, 1, 1, 1], [0, 0, 0, 0, 1], [0, 0, 0, 1, 1]] sum(x,y) #=>[[0, 1, 2, 2, 1], [0, 2, 0, 0, 2], [1, 2, 2, 2, 2], [0, 0, 0, 1, 2], [0, 0, 0, 2, 1]]
とうまくいきました。どちらも1行で綺麗にかけたので満足でした。講義のレポートはまだ終わってないんですが。。。こうやって綺麗にかけるとなんかやっぱruby楽しい!ってなりますね。行列計算とか綺麗に書きたい方の参考になったらなと思います。