gihyo.jpの「具体例で学ぶ!情報可視化のテクニック」のプログラムを勝手にRubyで書き換えてみた。
gihyo.jpで情報可視化の特集をやってて、すごく勉強になってよかったんですけど、
プログラムがJavaで書かれてて、個人的にRubyでやりたかったんで、
勉強ついでにプログラムをRubyで書き換えてみました。
そのRubyのプログラムはGithubにおいてあるので、ご自由にお使いください。
以下のリンクのdownloadからzip、またはtarで固めたものがダウンロードできます。
GitHub - ombran/gihyojp-visualization-ruby: The Ruby version of the information visualization introduced by gihyo.jp.(unofficial)
とまあ、さすがにこれで終わるのはひどいので、プログラムの簡単な説明をします。
今回はvisualization2のフォルダにあるプログラムの説明をします。
ただしここでRubyはインストール済みであるものとします。
Rubyのインストールとかの記事はいろんなところにあるんでそっちを参考にしてください。
Linuxとかなら元々インストール済みだったりしますし。
visualization2の説明
元記事だと第2回にあたる内容になります。
このプログラムは簡単に言えば、色集合を最短距離法に基づいて階層的クラスタリングを行うものです。
詳しいことは元記事を見てもらったほうがわかりやすいと思います。
visualization2フォルダ内容
visualization2のフォルダ内容は以下のようになっています。
$ tree visualization2 visualization2
-- Demo.rb | |
-- Visualization | |
-- Cluster.rb | |
-- ClusterBuilder.rb | |
-- DistanceEvaluator.rb | |
-- Item.rb | |
-- MultiVector.rb | |
-- NearestDistanceEvaluator.rb | |
`-- Node.rb |
拡張子の違いはありますが、元記事のプログラムのファイル名と内容を対応させてあります。
Visualization.rbを読み込むことだけで、Visualizationフォルダ以下のファイルを全て読み込めるようにしてあります。
元記事のプログラムとの違い
プログラムの内容自体はさほど違いはないんですけど、
元プログラムと大きく違うところとしてMultiVectorクラスの引数がハッシュになっています。
# MultiVector.rb module Visualization class MultiVector # ベクトル生成(引数はハッシュ) def initialize(hash={}) @data = {} hash.each do |key, value| @data[key] = value end end ... end
これはベクトルの次元数が違うもの同士でもクラスタリングできるようにするためです。
ちなみに今回はベクトルの次元数が全て同じなのでこの利点が実感できませんが、
visualization6ではこれによって元記事のプログラムで用いられているクラスを一つ削減できるようになっています。
まあとりあえずハッシュのほうが便利だよ、とでも思っておいてください。
その他のクラスでは言語の違いはありますが内容にほとんど変化はありません。
ただし、全てのクラスはVisualizationモジュール内に含まれるようにしてあります。
Javaでのパッケージの代わりだと考えてください。
デモプログラムの実行
それではプログラムのデモを行うDemoクラスは以下のようになります。
# Demo.rb require File.dirname(__FILE__) + '/Visualization' class Demo include Visualization def run # 入力データ作成 input = [] color = Struct.new(:red, :green, :blue) input << Item.new("BLUE", colorToVector(color.new(0, 0, 255))) input << Item.new("CYAN", colorToVector(color.new(0, 255, 255))) input << Item.new("MAGENTA", colorToVector(color.new(255, 0, 255))) input << Item.new("ORANGE", colorToVector(color.new(255, 200, 0))) input << Item.new("PINK", colorToVector(color.new(255, 175, 175))) input << Item.new("RED", colorToVector(color.new(255, 0, 0))) # 最短距離法に基づく階層的クラスタリングを準備 evaluator = NearestDistanceEvaluator.new builder = ClusterBuilder.new(evaluator) # クラスタリングを実行 result = builder.build(input) # クラスタリング結果を表示 output(result, 0) end def colorToVector(c) # 色成分を3次元のベクトルに変換 MultiVector.new({:red => c.red, :green => c.green, :blue => c.blue}) end def output(node, depth) # インデントを表示 depth.times do print " " end if (node.kind_of? Item) # 末端ノードなら項目名を表示 puts node.getName elsif (node.kind_of? Cluster) # クラスタなら"+"を表示し、子ノードを再帰的に表示 puts "+" cluster = node output(cluster.getLeft, depth + 1) output(cluster.getRight, depth + 1) end end end demo = Demo.new demo.run
入力データの色情報はRGBの値をそのまま入力してあります。
Demoクラスを実行すると,以下の出力が得られます。
$ ruby Demo.rb + + RED + MAGENTA + ORANGE PINK + BLUE CYAN
結果は元記事と同じになってるんで、プログラムは合ってると思うんですが、
もし何か間違い等ありましたら教えていただけるとありがたいです。
以上
今回はここまでです。
ほんとに簡単な説明で申し訳ないですけど、
元記事のプログラムと対応させて見てもらえるとわかりやすいかなと思います。
他のプログラムに関しては次回以降に説明します。