『機械学習のエッセンス(http://isbn.sbcr.jp/93965/)』のPythonサンプルをJuliaで書き換えてみる。（第04章07データの可視化）

# はじめに

[『機械学習のエッセンス(http://isbn.sbcr.jp/93965/)』のPythonサンプルをJuliaで書き換えてみる。（第04章06乱数）](https://qiita.com/yshutaro/items/3076d097cd2d4cf92089)の続きです。

# 前提・準備

ここではJuliaのパッケージ`Plots`を使います。
本の第02章に書かれているのと同様、なるべくファイル実行とREPLで試しているので`Jupyter Notebook`は使用していません。
※環境等については一番最後に補足で書きました。

## Plotsパッケージのインストール

```julia
julia> using Pkg

julia> Pkg.add("Plots")
```

しばらく時間がかかります。

## Plotsパッケージの確認

次の関数が表示できるか確認します。

```math
f(x) = exp(x)
```

```julia
julia> using Plots

julia> f(x) = exp(x)
f (generic function with 1 method)

julia> plot(f)
```

下記のように表示されれば、以降のサンプルは確認できるはずです。

![スクリーンショット 2019-01-19 11.25.39.png](https://qiita-image-store.s3.amazonaws.com/0/66839/71adbc95-4851-76f6-ca11-4f74f8e66c5a.png)

デフォルトでは`GR`というパッケージで描画するようです。
https://docs.juliaplots.org/latest/examples/gr/

# 折れ線グラフ

```plot1.jl 
using Plots

x = [0, 1, 2, 3]
y = [3, 7, 4, 8]

plot(x, y, color="red")
```

## 実行結果

```julia
julia> include("plot1.jl")
```

![スクリーンショット 2019-01-19 21.16.30.png](https://qiita-image-store.s3.amazonaws.com/0/66839/466db6ce-5b75-f439-5e1a-d41e1f3f0691.png)

ラベル`y1`が表示されていますが気にしないで進めます。

# 散布図

```scatter1.jl
using Plots

x = [0, 1, 2, 3]
y = [3, 7, 4, 8]

scatter(x, y, color="red")
```

## 実行結果

```julia
julia> include("scatter1.jl")
```

![スクリーンショット 2019-01-19 21.22.58.png](https://qiita-image-store.s3.amazonaws.com/0/66839/d7a94e02-e895-1bd2-ef66-f8f6896644d0.png)

# 曲線のグラフ

```math
y = x^2
```

Juliaでグラフについて調べたところ曲線は（数式風に記載した）関数そのものを指定すれば描画できるようです。（パッケージインストール確認の$f(x) = exp(x)$が例です）。Pythonで区間の点を多数取っているのはそれができないのでしょうか。あるいは、もしかしたら機械学習では大量のデータから曲線を描画することがあるのかもしれないので、本と同じ「点から描画する方法」と、「（数式風）関数でそのまま描画する方法」の2通りで書いてみました。

+ 点から描画する

```plot2-1.jl
using Plots

x = collect(LinRange(-5, 5, 300))
y = x.^2

plot(x, y, color="red")
```

+ 関数指定

```plot2-2.jl 
using Plots

f(x) = x^2

plot(f, color="red")
```

## 実行結果

```julia
julia> include("plot2-1.jl")
```

![スクリーンショット 2019-01-19 22.58.52.png](https://qiita-image-store.s3.amazonaws.com/0/66839/b7f2ed15-5fc8-dc98-046b-e2ca18b7e138.png)

```julia
julia> include("plot2-2.jl")
```

![スクリーンショット 2019-01-19 23.04.48.png](https://qiita-image-store.s3.amazonaws.com/0/66839/e29d36f6-c389-5059-d753-409859a8d82b.png)

### 参考

`@time`を付けると実行時間を計れるので2つを比較してみました。

```julia
julia> @time include("plot2-1.jl")
  0.003481 seconds (2.66 k allocations: 201.438 KiB)

julia> @time include("plot2-2.jl")
  0.523554 seconds (578.27 k allocations: 28.183 MiB, 1.45% gc time)
```

詳しいメッセージがわからないので断定は出来ませんが、上記の2通りなら点から描画する方が早いようです。

**以降は関数指定の方法だけにします。**

# 複数の線を表示する

```plot3.jl
using Plots

f(x) = x^2
g(x) = (x-2)^2

plot(f, color="red", label="f")
plot!(g, color="black", linestyle=:dash, label="g")
```

+ `plot`に続けて`plot!`を指定することで元のグラフに追加できました。
+ `plot`の引数に`linestyle`を指定すると線の形式が変更できました。次の種類があります。`:auto, :solid, :dash, :dot, :dashdot, :dashdotdot`

## 実行結果

```julia
julia> include("plot3.jl")
```

![スクリーンショット 2019-01-20 0.34.51.png](https://qiita-image-store.s3.amazonaws.com/0/66839/469ef08d-a3b2-8e39-c110-4477e605c84c.png)

# ヒストグラム

```hist1.jl
using Plots
using Random

Random.seed!(0)
l = []
for i in 1:1000
  append!(l, sum(rand(1:6, 10)))
end

histogram(l, bins=20, color="gray")
```

ビンの指定は下記を参照しました。
https://docs.juliaplots.org/latest/attributes/

## 実行結果

```julia
julia> include("hist1.jl")
```

![スクリーンショット 2019-01-20 23.31.34.png](https://qiita-image-store.s3.amazonaws.com/0/66839/5443d008-8b10-6d8f-3a32-feff11aaa104.png)

# 複数のグラフを並べて表示する

2つの`plot`と`layout`を指定することで並べて表示することが出来ました。

```subplot1.jl
using Plots

f(x) = sin(x)
g(x) = cos(x)

p1 = plot(f, color="red", label="sin(x)")
p2 = plot(g, color="black", label="cos(x)")
plot(p1, p2, layout=(2,1))
```

## 実行結果

```julia
julia> include("subplot1.jl")
```

![スクリーンショット 2019-01-21 21.46.12.png](https://qiita-image-store.s3.amazonaws.com/0/66839/b43b2c2c-dd86-e95a-ed45-8ff46032d1a5.png)

+ 本の`subplots2.py`はMatplotlibの説明なので省略します。

# 等高線の描画

```math
x^2 + \frac{y^2}{4} = k
```

楕円の方程式をyについて解くと、

```math
y = \pm2\sqrt{k - x^2}
```

となって一意に定まらないため数学での関数にならず、今まで通りのJuliaの数式風関数指定ではうまくいきません。

試しに、$\pm$を使って定義してみました。

+ $k = 1$のとき

```julia
julia> f(x) = ±2sqrt(1 - x^2)
ERROR: syntax: "±" is not a unary operator
```

当然ですがエラーになります。

そのため、本に記載されているように`mashgrid`を使う方法を調べたところ下記の黒木玄さんのTweetを見つけました。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr"><a href="https://twitter.com/hashtag/Julia%E8%A8%80%E8%AA%9E?src=hash&amp;ref_src=twsrc%5Etfw">#Julia言語</a> しかし、<br><br>z = f.(x_grid, y_grid)<br><br>と<br><br>z = f.(x&#39;,y)<br><br>は同じ結果になるので、x,yの要素の組にfを作用させて行列を作りたいなら、meshgridは必要ありません。<br><br>meshgridを流行らせた人達は無駄で効率が悪いものを流行らせて技術社会に負の貢献をしたと評価されるべきだと思います。</p>&mdash; 黒木玄 Gen Kuroki (@genkuroki) <a href="https://twitter.com/genkuroki/status/983226825332572160?ref_src=twsrc%5Etfw">2018年4月9日</a></blockquote>

※私がJuliaという言語を知ったのも黒木さんのTweetでした。

ということで、`z = f.(x',y)`の記述をもとに作成してみました。
等高線は`contour`という関数がありました。

```contour1.jl
using Plots

f(x, y) = x^2 + y^2 / 4

x = LinRange(-5, 5, 300)
y = LinRange(-5, 5, 300)

z = f.(x', y)

contour(z, levels=[1,2,3,4,5])
```

## 実行結果

```julia
julia> include("contour1.jl")
```

![スクリーンショット 2019-01-22 21.21.19.png](https://qiita-image-store.s3.amazonaws.com/0/66839/68997136-5276-e308-17e2-6240726216a2.png)

うまく表示できました。
が、目盛がPythonの場合とだいぶ違います。これはJuliaの`Plot`の特徴でしょうか。~~`LinRange`で指定する数値をいろいろ変えてみましたが、本と似たような目盛にはできませんでした。一旦、このまま進めます。~~
（追記） `contour` 関数の最初の引数に`x`と`y`を入れたところ-5〜5で表示が出来ました。


```contour1_1.jl
using Plots

f(x, y) = x^2 + y^2 / 4

x = LinRange(-5, 5, 300)
y = LinRange(-5, 5, 300)

z = f.(x', y)

contour(x, y, z, levels=[1,2,3,4,5])
```

```julia
julia> include("contour1_1.jl")
```

![スクリーンショット 2019-02-01 20.52.41.png](https://qiita-image-store.s3.amazonaws.com/0/66839/f5260b80-3d12-a6e5-992f-06ba4f22dc31.png)


+ f.(x', y)の動きを確認

本では`meshgrid`について詳しく書かれているので、ここでは`f.(x', y)`を確認してみます。

```julia
julia> x = [1, 2, 3]
3-element Array{Int64,1}:
 1
 2
 3

julia> y = [4, 5, 6]
3-element Array{Int64,1}:
 4
 5
 6

julia> x1 = x'
1×3 LinearAlgebra.Adjoint{Int64,Array{Int64,1}}:
 1  2  3

julia> f(x, y) = x * y
f (generic function with 2 methods)

julia> x' .* y
3×3 Array{Int64,2}:
 4   8  12
 5  10  15
 6  12  18

julia> f.(x', y)
3×3 Array{Int64,2}:
 4   8  12
 5  10  15
 6  12  18
```

`x`と`y`は配列なので、定義したときは`3 x 1`の配列で、`x'`は転置なので`1 x 3`の配列ですが、それを`f`に`.`付き、つまりブロードキャストで渡すと`3 x 3`になりました。
（なんだか不思議です。まだブロードキャストをよく理解できていないようです。）

$f(x, y) = x^2 + y^2 / 4$でも試してみます。

```julia
julia> x = [1, 2, 3]
3-element Array{Int64,1}:
 1
 2
 3

julia> y = [4, 5, 6]
3-element Array{Int64,1}:
 4
 5
 6

julia> f(x, y) = x^2 + y^2 / 4
f (generic function with 2 methods)

julia> f.(x', y)
3×3 Array{Float64,2}:
  5.0    8.0   13.0 
  7.25  10.25  15.25
 10.0   13.0   18.0 
```


+ 領域の塗り分け

領域を塗る等高線はPythonと同様`contourf`という関数がありました。
~~が・・・、色の指定が全然うまくいかず、いろいろ数値を変えたり調べたりしましたが、グラデーションがかかったようなはっきりしない色しか出来ませんでした。~~
（追記）これも上記と同じく、目盛表示を-5〜5にしたらうまく表示できました。

```contour2.jl
using Plots

f(x, y) = x^2 + y^2 / 4

x = LinRange(-5, 5, 300)
y = LinRange(-5, 5, 300)

z = f.(x', y)

colors = [0.1, 0.3, 0.5, 0.7]
levels = [1, 2, 3, 4, 5]
contourf(z, fill=(true,cgrad(:grays,colors)), levels=levels)
```

## 実行結果

```julia
julia> include("contour2.jl")
```

+ グレーで指定した場合

なんだか境界線がよくわからないですね。
（目盛表示を変更したらうまくいきました。追記してあります。）

![スクリーンショット 2019-01-22 22.32.41.png](https://qiita-image-store.s3.amazonaws.com/0/66839/3ae5a277-32c1-a4c6-92f1-63068d405ad3.png)

+ （追記）目盛を変更した場合

```contour2_1.jl
using Plots

f(x, y) = x^2 + y^2 / 4

x = LinRange(-5, 5, 300)
y = LinRange(-5, 5, 300)

z = f.(x', y)

colors = [0.1, 0.3, 0.5, 0.7]
levels = [1, 2, 3, 4, 5]
contourf(x, y, z, fill=(true,cgrad(:grays,colors)), levels=levels)
```


```julia
julia> include("contour2_1.jl")
```

![スクリーンショット 2019-02-01 20.57.17.png](https://qiita-image-store.s3.amazonaws.com/0/66839/3a982c20-9cb6-d171-38b1-082c7ec03aee.png)



+ 色を指定しないデフォルトの場合

`contourf`の部分を下記のようにした場合です。

```julia
contourf(z, levels=levels)
```

色は派手ですが、やはり境界線がはっきりせずグラデーションになっています。
（追記）目盛を変えたらこちらもうまくいきました。追記してあります。

![スクリーンショット 2019-01-22 22.37.15.png](https://qiita-image-store.s3.amazonaws.com/0/66839/e29992fe-7607-559b-ca25-3f2fc012a4e1.png)

+ （追記）目盛を変更した場合

はっきりときれいな色分けができています。

![スクリーンショット 2019-02-01 21.04.16.png](https://qiita-image-store.s3.amazonaws.com/0/66839/a98b414c-9a25-e919-bf7a-8ed307fa8d16.png)


+ メッシュを荒くした場合

ためしに、下記のように点を荒くして試してみました。

```julia
x = LinRange(-5, 5, 10)
y = LinRange(-5, 5, 10)
```

![スクリーンショット 2019-01-22 22.40.22.png](https://qiita-image-store.s3.amazonaws.com/0/66839/3cdbb4ec-5b14-6f0e-faac-b2f62f88b0b4.png)

全然ダメですね。
（追記）こちらも試しに目盛を修正してみました。色はきれいですが一部変な形になりました。

![スクリーンショット 2019-02-01 21.07.51.png](https://qiita-image-store.s3.amazonaws.com/0/66839/16a36cf3-a2bc-84e8-51b3-dad19e34cb48.png)


~~塗り分けについては一旦保留することにします。~~
（追記）目盛の変更の仕方がわかったので上記に追記してあります。

# 補足

+ サンプルを確認した環境はMacです。
+ Windows10でもJuliaの`.exe`でインストールしたものでは、セキュリティの警告が出ますが、許可すると表示されました。
+ `bash on ubuntu on windows`にJuliaをインストール（`.tar.gz`を展開）したものはエラーが出て表示されませんでした。（解決方法については調べていません。）

+ `GR`でない別のパッケージを入れた後、下記のエラーが出て描画が出来なくなりました。

```julia
ERROR: error compiling _plot!: error compiling _display: could not load library "libGR.so"
dlopen(libGR.so.dylib, 1): image not found
```

下記で解決しました。

```julia
julia> ENV["GRDIR"]=""

julia> using Pkg

julia> Pkg.build("GR")
```