Julia1.0で学ぶ数理統計学（①函数と、その比較）

#数式書くのがはかどるJulia
いずれ統計検定なるものを受けておこうと思ったため、週末に少しずつ数理統計学を学んでいく。数理、とつくものを学ぶからには、数式の書きやすくてモダンな言語、ということで、最近にバージョン1.0が出たjuliaを使いつつ学んでいくことにした。今更ながら、数学をお勉強しようという人にはJuliaおすすめと思った。統計パッケージや機械学習パッケージも充実しつつあるようだし。学生さんにもおすすめかと。

julia自体はじめてなので、まずは、juliaの関数（函数）表現を学ぶこととした。

主に参考にしたのは、[Juliaの関数について](https://qiita.com/phigasui/items/0f1becf4555d7f1fe728)。こちら、Juliaの関数を簡潔にまとめた良記事。
ただ、個人的にキーワードとしてのfuntionを使うのが好きではないし、数学・統計学している気分が出ないので、僕の方では数学的な表現(eg. f(x,y))だけを用いてコードを表記していく方法を追求していくこととした。以下、julia における、こうした数学的な表現方法を数学通（？）っぽく「函数」と呼ぶことにする。

以下、juliaのREPLを用いていく。
なお、バージョン1.0記念でインストール記事はいくつもあるので、そのあたりは略（windows10 64bitでは、公式のインストーラー経由ですぐインストールできた）。

#シンプルな函数

はじめに３つの函数f(x), g(x), h(x)を定義する。
数式:
$$
f(x) = x^2 + 2x + 1
$$

$$
g(x) = (x + 1)
$$

$$
h(x) = (x + 1) (x + 1)
$$

コード:

```.py
julia> f(x) = x^2 +2x + 1
f (generic function with 2 methods)

julia> g(x) = (x + 1)
g (generic function with 1 method)

julia> h(x) = (x + 1) * (x + 1)
h (generic function with 1 method)
```

表記上の注意点:

```.py
f(x) = x^2 +2x + 1         #juliaでは、2*x の代わりに2xと書ける。
h(x) = (x + 1) * (x + 1)   #juliaでは、(x + 1)(x + 1)とは書けない。
```

juliaに関する記事でみなさんが書いているどおり、xは整数でも実数でも虚数でも良い。juliaでは虚数はimと表記。

```.py
julia> f(1)
4
julia> f(im)
0 + 2im

julia> h(1)
4
julia> g(1)
2

julia> g(im)
1 + 1im
julia> h(im)
0 + 2im
```

多少ものぐさな書き方も許してくれるようだ。

```.py
julia> h(0.2+ 0.3im)
1.3499999999999999 + 0.72im

julia> h(.2+ .3im)
1.3499999999999999 + 0.72im
```

#複合的な函数
 
let～endでブロックをつくると、より複雑なコードを函数化できる。

```.py
f(x) = let
　もろもろのコード
end
```

##例①　複数の数式を含む函数

```.py

julia> hoge(x) = let
           x = x^2
           x + 1
       end
hoge (generic function with 1 method)

julia> hoge(2)
5

```

##例②ループを含む函数

見やすさのため、函数と実行結果とを分けて書いておく。
函数定義:

```.py
f(x, y) = let
    for i in 1:y
        x = x * i
    end
    x #返り値
end
```
実行結果:

```.py
julia> for y in 1:3
           ret = f(2,y)
           println("y:",y, " -> ", ret)
       end
y:1 -> 2
y:2 -> 4
y:3 -> 12
```

返り値をタプル(x,y)とすることもできる。手抜きの例だけれど:

函数定義:

```.py
f(x, y) = let
    for i in 1:y
        x = x * i
    end
    (x, y ^ 2)
end
```
実行結果:

```.py
julia> for y in 1:3
           ret = f(2,y)
               println("y:",y, " -> ", ret)
               end
y:1 -> (2, 1)
y:2 -> (4, 4)
y:3 -> (12, 9)
```

#函数同士の比較！？
興味深いのが函数同士を比較できるらしいこと。上のシンプルな函数について比較演算子を使ってみると、期待通りの結果が得られた。

```.py
julia> f(x) == g(x)
false

julia> f(x) == h(x)
true
```

複雑な函数表現はおそらく無理だろうけど。

##複雑な函数同士の比較

ということで、より複雑な函数同士を比較してみた。ベイズ統計などでよく使われるtanh（ハイパボリックタンジェント）な函数と同等なシグモイド関数との比較をしてみよう。


まずは、手慣らしにjuliaでtanh。振る舞いは以下のような感じ

```.py
julia> i(x) = tanh(x)
i (generic function with 1 method)

julia> i(1.0)
0.7615941559557649

julia> i(100000000000)
1.0

julia> i(1000000)
1.0

julia> i(-1000000)
-1.0

julia> i(0)
0.0

julia> i(-1)
-0.7615941559557649
```

続いて、juliaのシグモイド関数。

数学的には、シグモイド関数は２通りに表現できる。
$$
sigmoid(z) =  \frac{1}{1 + exp(-z)} = \frac{1 + tanh(\frac{x}{2})}{2}
$$
> 参考　[シグモイド関数の意味と簡単な性質](https://mathtrain.jp/sigmoid)

この２つの函数表現を比べる。

はじめにシグモイド関数の（指数（exp）を使った表現）:

```.py
julia> sigmoid(z) =  1.0 / (1.0 + exp(-z))
sigmoid (generic function with 1 method)

julia> sigmoid(0)
0.5

julia> sigmoid(1)
0.7310585786300049

julia> sigmoid(-1)
0.2689414213699951

julia> sigmoid(100000)
1.0

julia> sigmoid(-100000)
0.0
```

続いて、シグモイド関数のtanhを用いた表現:

```.py
julia> sigmon2(x) =  (1.0 + tanh(x / 2 )) / 2
sigmon2 (generic function with 1 method)

julia> sigmon2(0)
0.5

julia> sigmon2(1)
0.7310585786300049

julia> sigmon2(-1)
0.2689414213699951

julia> sigmon2(100000)
1.0

julia> sigmon2(-100000)
0.0

```

計算結果は同一だ。さてさて...

```.py
julia> sigmoid == sigmon2
false
```
やっぱ、無理だったw

#感想
数学的な厳密さなどはさておき、julia、プログラマの期待を裏切らない数式記述言語として学んでおいてもよさそうだ。次回はpythonとの相互呼び出しあたりに挑戦。