Rubyで散布図行列（ペアプロット）を作る

## はじめに
Rubyでペアプロットを作る場合のスニペット。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/144608/92248ea1-8b8a-2935-2d44-f79fc72fa3ee.png)

Google colaboratory で実行した場合
(改良前なので若干上と画像が違います）
![image.png](https://qiita-image-store.s3.amazonaws.com/0/144608/102458ee-2b1e-dc23-0150-8ff42136007d.png)

## 環境
* Jupyter Notebook
* IRuby
* [Daru::View](https://github.com/SciRuby/daru-view)

（Jupyter Notebook や IRuby の導入は済んでいるものとします）
あと、一応Google Colaboratoryを使うという手段もあります。

## iris 読み込み
ここではrdatasets Gemを使う。

```ruby
require 'daru'
require 'daru/view'
require 'rdatasets'

iris = RDatasets.load :datasets, :iris
iris.head(3)

Daru::View.plotting_library = :googlecharts # Google Colab ではその都度指定する必要あり
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/144608/9ac7ffd4-1bce-f95b-96dd-07d00b4945ad.png)

##ペアプロットを描く その1

```ruby
# Daru::View.plotting_library = :googlecharts # Google Colab ではその都度指定する必要あり

vector_names = iris[0..3].vectors.to_a

vector_names.each do |row|
  plots = vector_names.map do |column|
    if row != column
      Daru::View::Plot.new(iris[column, row],
                           type: :scatter,
                           height: 100,
                           width: 100,
                           pointSize: 1)
    else
      Daru::View::Plot.new(iris[row],
                           title: row,
                           height: 100,
                           width: 100,
                           type: :histogram)
    end
  end
  IRuby.display Daru::View::PlotList.new(plots).show_in_iruby
end
```
普通に頑張ってループまわして描いた感じです。これでも実用にたえると思いますが、見た目がややチープですね。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/144608/e4be77e5-b010-34ac-c533-007737c4830f.png)


## ペアプロットを描く その2
とりあえず見た目を改善します。
（なお「見た目」とは、コードの見た目ではなく、プロットの見た目のことを指しています）

```ruby
# Daru::View.plotting_library = :googlecharts # Google Colab ではその都度指定する必要あり

vector_names = iris[0..3].vectors.to_a

opts = {
  chartArea: { left: 5, right: 5, top: 5, bottom: 5 },
  height: 100,
  width: 100,
  hAxis: {viewWindowMode: "maximized"},
  vAxis: {viewWindowMode: "maximized"},
  backgroundColor: '#f0f0f0',
  gridlineColor: 'white',
  colors: ['#4784BF']
}

vector_names.each do |row|
  plots = vector_names.map do |column|
    if row != column

      Daru::View::Plot.new(iris[column, row], opts.merge(
                                                type: :scatter,
                                                pointSize: 1
                                              ))
    else
      Daru::View::Plot.new(iris[row], opts.merge(
                                        title: row,
                                        titlePosition: 'in',
                                        type: :histogram
                                      ))
    end
  end
  IRuby.display Daru::View::PlotList.new(plots).show_in_iruby
end
```
Seabornをリスペクトしてみました。先程よりも見やすくなったかと思います。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/144608/92248ea1-8b8a-2935-2d44-f79fc72fa3ee.png)

## 関数にしてみた
ほとんど何も変わっていない。

```ruby
def pair_plot(df, width: 100, height: 100, color: '#4784BF')
  vector_names = df.only_numerics.vectors.to_a

  opts = {
    chartArea: { left: 5, right: 5, top: 5, bottom: 5 },
    height: height,
    width: width,
    hAxis: { viewWindowMode: 'maximized' },
    vAxis: { viewWindowMode: 'maximized' },
    backgroundColor: '#f0f0f0',
    gridlineColor: 'white',
    colors: [color],
    adapter: :googlecharts
  }

  vector_names.each do |row|
    plots = vector_names.map do |column|
      if row != column

        Daru::View::Plot.new(
          df[column, row], opts.merge(type: :scatter,
                                      pointSize: 1)
        )
      else
        Daru::View::Plot.new(
          df[row], opts.merge(title: row,
                              titlePosition: 'in',
                              type: :histogram)
        )
      end
    end
    IRuby.display Daru::View::PlotList.new(plots).show_in_iruby
  end
end
```

## Rのデータセットをペアプロットしてみよう

### USArrests
```ruby
require 'rdatasets'
df = RDatasets.datasets.USArrests
pair_plot(df, color: "green")
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/144608/f3300c21-9ff0-7522-a288-a6997cd68277.png)

### fgl

```ruby
df = RDatasets.MASS.fgl
pair_plot(df, height:60, width: 60)
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/144608/f77d1a0f-b267-729e-7711-3cf8e6286d8e.png)


こんな感じで、描けるか描けないかでいったら、描ける。

## おまけ
Species ごとに平均などを見たい場合は `group_by`

```ruby
iris.Species.to_category
hoge = iris.group_by ["Species"]
hoge.mean
# hoge.max
# hoge.min
# hoge.median
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/144608/bad62a24-34a0-79b9-27c5-a88aa4f09b96.png)