『機械学習のエッセンス(http://isbn.sbcr.jp/93965/)』のPythonサンプルをJuliaで書き換えてみる。（第04章03配列の基本計算）

# はじめに

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

## いろいろな集計関数

+ 合計（sum）
+ 最大値（maximum）
+ 最小値（minimum）

Juliaでは配列の最大値、最小値は`max`、`min`ではなくそれぞれ`maximum`、`minimum`でした。

```julia
julia> a = collect(0:4)
5-element Array{Int64,1}:
 0
 1
 2
 3
 4

julia> sum(a)
10.0

julia> maximum(a)
4.0

julia> minimum(a)
0.0
```

+ 平均（mean）

`mean`は`Base`モジュールではなく`Statistics`モジュールで定義されています。

```julia
julia> using Statistics

julia> mean(a)
2.0
```

## 2次元配列の合計

```julia
julia> b = reshape(collect(0.:8.), 3, 3)
3×3 Array{Float64,2}:
 0.0  3.0  6.0
 1.0  4.0  7.0
 2.0  5.0  8.0

julia> sum(b)
36.0
```

+ 列ごとの合計
+ 行ごとの合計

Juliaの`reshape`はPythonと見た目が転置状態なので、それぞれ本とは値が逆になっています。また`axis`ではなく`dims`で指定するようです。

```julia
julia> sum(b, dims=1)
1×3 Array{Float64,2}:
 3.0  12.0  21.0

julia> sum(b, dims=2)
3×1 Array{Float64,2}:
  9.0
 12.0
 15.0
```

# ブロードキャスト

```julia
julia> a = collect(3.:7.)
5-element Array{Float64,1}:
 3.0
 4.0
 5.0
 6.0
 7.0

julia> exp(a)
ERROR: MethodError: no method matching exp(::Array{Float64,1})
Closest candidates are:
  exp(::BigFloat) at mpfr.jl:558
  exp(::Missing) at math.jl:1070
  exp(::Complex{Float16}) at math.jl:1019
```

Juliaでは直接関数を指定してもブロードキャストしないようです。明示的に指定する`broadcast(Base.Broadcast.broadcast )`という関数がありました。
あるいは、もっと簡単に関数に`.`（ドット）を付けるとできます。

```julia
julia> broadcast(exp, a)
5-element Array{Float64,1}:
   20.085536923187668
   54.598150033144236
  148.4131591025766  
  403.4287934927351  
 1096.6331584284585

julia> exp.(a)
5-element Array{Float64,1}:
   20.085536923187668
   54.598150033144236
  148.4131591025766  
  403.4287934927351  
 1096.6331584284585 

julia> broadcast(log, a)
5-element Array{Float64,1}:
 1.0986122886681098
 1.3862943611198906
 1.6094379124341003
 1.791759469228055 
 1.9459101490553132

julia> log.(a)
5-element Array{Float64,1}:
 1.0986122886681098
 1.3862943611198906
 1.6094379124341003
 1.791759469228055 
 1.9459101490553132

julia> broadcast(sqrt, a)
5-element Array{Float64,1}:
 1.7320508075688772
 2.0               
 2.23606797749979  
 2.449489742783178 
 2.6457513110645907

julia> sqrt.(a)
5-element Array{Float64,1}:
 1.7320508075688772
 2.0               
 2.23606797749979  
 2.449489742783178 
 2.6457513110645907
```

```julia
julia> b = reshape(collect(0.:8.), 3, 3)
3×3 Array{Float64,2}:
 0.0  3.0  6.0
 1.0  4.0  7.0
 2.0  5.0  8.0

julia> broadcast(exp, b)
3×3 Array{Float64,2}:
 1.0       20.0855   403.429
 2.71828   54.5982  1096.63 
 7.38906  148.413   2980.96 

julia> exp.(b)
3×3 Array{Float64,2}:
 1.0       20.0855   403.429
 2.71828   54.5982  1096.63 
 7.38906  148.413   2980.96 
```
## 配列とスカラの演算

やはり`+`でも直接はダメですね。

```julia
julia> a = collect(0:4)
5-element Array{Int64,1}:
 0
 1
 2
 3
 4

julia> a + 3
ERROR: MethodError: no method matching +(::Array{Int64,1}, ::Int64)
Closest candidates are:
  +(::Any, ::Any, ::Any, ::Any...) at operators.jl:502
  +(::Complex{Bool}, ::Real) at complex.jl:292
  +(::Missing, ::Number) at missing.jl:93
  ...
Stacktrace:
 [1] top-level scope at none:0
```

下記のように`broadcast`に演算子と引数を指定するか、演算子に`.`（ドット）を付けるとできます。

```julia
julia> broadcast(+, 3, a)
5-element Array{Int64,1}:
 3
 4
 5
 6
 7

julia> a .+ 3
5-element Array{Int64,1}:
 3
 4
 5
 6
 7

julia> broadcast(*, 3, a)
5-element Array{Int64,1}:
  0
  3
  6
  9
 12

julia> a .* 3
5-element Array{Int64,1}:
  0
  3
  6
  9
 12

julia> broadcast(^, 2, a)
5-element Array{Int64,1}:
  1
  2
  4
  8
 16

julia> a .^ 2
5-element Array{Int64,1}:
  0
  1
  4
  9
 16
```

+ 条件式の場合

演算子のように`.`（ドット）を付けてできます。

```julia
julia> a .>= 2
5-element BitArray{1}:
 false
 false
  true
  true
  true

julia> a .!= 3
5-element BitArray{1}:
  true
  true
  true
 false
  true

julia> b = reshape(collect(0:8), 3, 3)
3×3 Array{Int64,2}:
 0  3  6
 1  4  7
 2  5  8

julia> b .> 3
3×3 BitArray{2}:
 false  false  true
 false   true  true
 false   true  true
```

## ブール値を要素として持つ配列の演算

```julia
julia> a = [10, 20, 30, 40]
4-element Array{Int64,1}:
 10
 20
 30
 40

julia> b = [false, true, true, false]
4-element Array{Bool,1}:
 false
  true
  true
 false

julia> a[b]
2-element Array{Int64,1}:
 20
 30
```

```julia
julia> c = [3 4 5; 6 7 8]
2×3 Array{Int64,2}:
 3  4  5
 6  7  8

julia> d = [false false true; false true true]
2×3 Array{Bool,2}:
 false  false  true
 false   true  true

julia> c[d]
3-element Array{Int64,1}:
 7
 5
 8
```

最後の結果がPythonと順番が違います。本では`array([5, 7, 8])`です。Juliaの場合、行列の順番通りに数えるようです。ここでは7と5と8がそれぞれ2行3列、3行1列、3行2列の順で配列を出力しています。
ちなみに、Pythonと同じように配列の配列で書くと下記のようにエラーになってしまいました。

```julia
julia> e = [[3,4,5],[6,7,8]]
2-element Array{Array{Int64,1},1}:
 [3, 4, 5]
 [6, 7, 8]

julia> f = [[false,false,true],[false,true,true]]
2-element Array{Array{Bool,1},1}:
 [false, false, true]
 [false, true, true] 

julia> e[f]
ERROR: ArgumentError: invalid index: Array{Bool,1}[[false, false, true], [false, true, true]] of type Array{Array{Bool,1},1}
Stacktrace:
 [1] to_index(::Array{Array{Bool,1},1}) at ./indices.jl:263
 [2] to_index(::Array{Array{Int64,1},1}, ::Array{Array{Bool,1},1}) at ./indices.jl:247
 [3] to_indices at ./indices.jl:294 [inlined]
 [4] to_indices at ./indices.jl:291 [inlined]
 [5] getindex(::Array{Array{Int64,1},1}, ::Array{Array{Bool,1},1}) at ./abstractarray.jl:905
 [6] top-level scope at none:0
```

## 条件を指定した要素の抽出

```julia
julia> a = collect(0:9)
10-element Array{Int64,1}:
 0
 1
 2
 3
 4
 5
 6
 7
 8
 9

julia> a[a .> 5]
4-element Array{Int64,1}:
 6
 7
 8
 9
```

+ 条件式の`&`と`|`

配列に`.`（ドット）付きの演算子を適用すると`BitArray`という配列が返ってきます。配列の演算なので`&`をそのまま使うとエラーになります。複数の条件の場合は同じく`.`を付けます。

```julia
julia> a .>= 3
10-element BitArray{1}:
 false
 false
 false
  true
  true
  true
  true
  true
  true
  true

julia> a .< 6
10-element BitArray{1}:
  true
  true
  true
  true
  true
  true
 false
 false
 false
 false

julia> (a .>= 3) & (a .< 6)
ERROR: MethodError: no method matching &(::BitArray{1}, ::BitArray{1})
Closest candidates are:
  &(::Any, ::Any, ::Any, ::Any...) at operators.jl:502
Stacktrace:
 [1] top-level scope at none:0

julia> (a .>= 3) .& (a .< 6)
10-element BitArray{1}:
 false
 false
 false
  true
  true
  true
 false
 false
 false
 false
```

```julia
julia> a[(a .>= 3) .& (a .< 6)]
3-element Array{Int64,1}:
 3
 4
 5

julia> a[(a .< 2) .| (a .> 7)]
4-element Array{Int64,1}:
 0
 1
 8
 9

julia> a[a .% 3 .!= 0]
6-element Array{Int64,1}:
 1
 2
 4
 5
 7
 8
```

# 配列の演算

## 配列同士の演算

```julia
julia> u = collect(0:3)
4-element Array{Int64,1}:
 0
 1
 2
 3

julia> v = collect(3:6)
4-element Array{Int64,1}:
 3
 4
 5
 6
```

配列同士ですが、`.`がなくても`+`と`-`は問題なくできました。
`.`を付けても同じ結果です。

```julia
julia> u + v
4-element Array{Int64,1}:
 3
 5
 7
 9

julia> u .+ v
4-element Array{Int64,1}:
 3
 5
 7
 9

julia> u - v
4-element Array{Int64,1}:
 -3
 -3
 -3
 -3

julia> u .- v
4-element Array{Int64,1}:
 -3
 -3
 -3
 -3
```

`*`は`.`なしだとエラーとなりました。`.`を付けるとできます。

```julia
julia> u * v
ERROR: MethodError: no method matching *(::Array{Int64,1}, ::Array{Int64,1})
Closest candidates are:
  *(::Any, ::Any, ::Any, ::Any...) at operators.jl:502
（略）

julia> u .* v
4-element Array{Int64,1}:
  0
  4
 10
 18
```

+ ベクトルの内積

`dot`関数は`LinearAlgebra`モジュールにあります。あるいは`⋅`（cdot）演算子を使います。`⋅`はREPL上で`\cdot`と打ってTABキーで変換できます。（`⋅`も`using LinearAlgebra`を実行しておかないと使えません。）


```julia
julia> sum(u .* v)
32

julia> using LinearAlgebra

julia> dot(u, v)
32

julia> u ⋅ v
32
```

## 2次元配列の演算

ここの計算は本の表示と合わせるために`reshape`関数のあとに`'`を付けて転置させました。

```julia
julia> a = reshape(collect(0.:8.),3, 3)'
3×3 Adjoint{Float64,Array{Float64,2}}:
 0.0  1.0  2.0
 3.0  4.0  5.0
 6.0  7.0  8.0

julia> b = reshape(collect(4.:12.), 3, 3)'
3×3 Adjoint{Float64,Array{Float64,2}}:
  4.0   5.0   6.0
  7.0   8.0   9.0
 10.0  11.0  12.0
```

+ `+`と`-`は`.`をつけなくても計算できますが、他と合わせて`.`を付けました。


```julia
julia> a .+ b
3×3 Array{Float64,2}:
  4.0   6.0   8.0
 10.0  12.0  14.0
 16.0  18.0  20.0

julia> a .- b
3×3 Array{Float64,2}:
 -4.0  -4.0  -4.0
 -4.0  -4.0  -4.0
 -4.0  -4.0  -4.0

julia> a .* b
3×3 Array{Float64,2}:
  0.0   5.0  12.0
 21.0  32.0  45.0
 60.0  77.0  96.0

julia> a ./ b
3×3 Array{Float64,2}:
 0.0       0.2       0.333333
 0.428571  0.5       0.555556
 0.6       0.636364  0.666667
```

+ `dot`関数

NumPyの`dot`は行列積となっていますが、Juliaで`dot`を使ってみたところ結果が違いました。

```julia
julia> using LinearAlgebra

julia> dot(a, b)
348.0
```

これは`sum(a .* b)`の結果と同じです。これは内積です。

```julia
julia> sum(a .* b)
348.0
```

行列積を計算したいときは`*`を使うようです。`.`をつけて`.*`とすると行列のそれぞれの要素をかけ算しますが、`*`だけだと行列の積になります。

```julia
julia> a * b
3×3 Array{Float64,2}:
  27.0   30.0   33.0
  90.0  102.0  114.0
 153.0  174.0  195.0
```

`+`と`-`はそれぞれの要素をプラス、マイナスするので`.`を付けても付けなくても結果が同じだったということですね。
Juliaの場合、行列のそれぞれの要素で計算したいときは演算子に`.`を付ける。行列として計算したいときは演算子に`.`を付けないようです。

## 形状の違う行列の積

ここは行列の形状の話なので、本には合わせずJuliaのそのままの出力で行います。本とはエラーなどの順番が違います。

```julia
julia> a = reshape(collect(0.:8.), 3, 3)
3×3 Array{Float64,2}:
 0.0  3.0  6.0
 1.0  4.0  7.0
 2.0  5.0  8.0

julia> v = collect(1.:3.)
3-element Array{Float64,1}:
 1.0
 2.0
 3.0
```

`3 x 3`行列と`3 x 1`行列（縦ベクトル）との計算になります。

+ 積を求める。`3 x 3`行列 `*` `3 x 1`行列 = `3 x 1`行列

```julia
julia> a * v
3-element Array{Float64,1}:
 24.0
 30.0
 36.0
```

+ 引数を逆にする。`3 x 1`行列 `*` `3 x 3`行列→エラー

```julia
julia> v * a
ERROR: DimensionMismatch("A has dimensions (3,1) but B has dimensions (3,3)")
Stacktrace:
（略）
```

+ `v`を転置させて形状を`1 x 3`行列に

```julia
julia> u = v'
1×3 LinearAlgebra.Adjoint{Float64,Array{Float64,1}}:
 1.0  2.0  3.0

julia> a * u
ERROR: DimensionMismatch("A has dimensions (3,3) but B has dimensions (1,3)")
Stacktrace:

julia> u * a
1×3 LinearAlgebra.Adjoint{Float64,Array{Float64,1}}:
 8.0  26.0  44.0
```

+ `v`の形状を`1 x 3`行列に。（Juliaだと最初の`v`が`3 x 1`の縦ベクトルなので`w`は`u`と同じです。）

```julia
julia> w = reshape(v, 1,:)
1×3 Array{Float64,2}:
 1.0  2.0  3.0

julia> w * a
1×3 Array{Float64,2}:
 8.0  26.0  44.0

julia> u * a
1×3 Adjoint{Float64,Array{Float64,1}}:
 8.0  26.0  44.0
```

## 配列同士の演算におけるブロードキャスト

ここではJuliaのそのままの出力とします。`a`の表示が本と転置状態なので計算結果は本と違います。

```julia
julia> a = reshape(collect(0.:11.), 4, 3)
4×3 Array{Float64,2}:
 0.0  4.0   8.0
 1.0  5.0   9.0
 2.0  6.0  10.0
 3.0  7.0  11.0

julia> b = reshape(collect(0.:2.), 1, 3)
1×3 Array{Float64,2}:
 0.0  1.0  2.0

julia> c = reshape(collect(0.:3.), 4, 1)
4×1 Array{Float64,2}:
 0.0
 1.0
 2.0
 3.0
```

+ `+`そのままではエラー

形状が一致しないときは`.`を付けないとエラーになりました。

```julia
julia> a + b
ERROR: DimensionMismatch("dimensions must match")
```

`.`を付ける

```julia
julia> a .+ b
4×3 Array{Float64,2}:
 0.0  5.0  10.0
 1.0  6.0  11.0
 2.0  7.0  12.0
 3.0  8.0  13.0

julia> a .* c
4×3 Array{Float64,2}:
 0.0   0.0   0.0
 1.0   5.0   9.0
 4.0  12.0  20.0
 9.0  21.0  33.0

julia> b .- c
4×3 Array{Float64,2}:
  0.0   1.0   2.0
 -1.0   0.0   1.0
 -2.0  -1.0   0.0
 -3.0  -2.0  -1.0
```

## 2次元配列と1次元配列の演算

```julia
julia> a = reshape(collect(0.:11.), 4, 3)
4×3 Array{Float64,2}:
 0.0  4.0   8.0
 1.0  5.0   9.0
 2.0  6.0  10.0
 3.0  7.0  11.0

julia> v = reshape(collect(0.:2.), 1, 3)
1×3 Array{Float64,2}:
 0.0  1.0  2.0

julia> a .+ v
4×3 Array{Float64,2}:
 0.0  5.0  10.0
 1.0  6.0  11.0
 2.0  7.0  12.0
 3.0  8.0  13.0
```