はじめに
『機械学習のエッセンス(http://isbn.sbcr.jp/93965/)』のPythonサンプルをJuliaで書き換えてみる。(第04章01数値計算の基本)の続きです。
※本との対比のため同じ見出しを付けていますが、NumPyではなくJuliaで書いているので以下の見出しからはNumPyは削除しています。
関数
- eのべき乗
- 自然対数
- 正弦
- 平方根
julia> exp(2)
7.38905609893065
julia> log(ℯ)
1
julia> sin(π)
1.2246467991473532e-16
julia> sqrt(3)
1.7320508075688772
Juliaは「π」とか「ℯ」がそのまま使えるのが面白いですね。
日本語IMEだと「π」は”ぱい(pai)”と打って変換できますが、「ℯ」はいろいろ試したのですが変換できず、調べたらREPL上で\euler
と打って、Tabキーを押して変換できるようです。
上記のlog(ℯ)
は
log(\euler
まで打ってここでTabキーを押すと
log(ℯ
となりました。π
は\pi
ですね。
配列
Juliaの配列のインデックスは「1」始まりなので、インデックス指定をするときPythonとは番号が異なります。なるべく本の結果と同じになるようにインデックスを調整しました。
julia> a = [2, 3, 5, 7, 8]
5-element Array{Int64,1}:
2
3
5
7
8
- 先頭の要素
julia> a[1]
2
- インデックス2〜3の要素
julia> a[2:3]
2-element Array{Int64,1}:
3
5
- インデックス3〜5-1=4までの要素
julia> a[3:-1]
0-element Array{Int64,1}
julia> a[3:end-1]
2-element Array{Int64,1}:
5
7
Juliaはインデックス「-1」は最後から−1の要素にならなく、end
が最後のインデックスなのでend-1
となります。
- range指定の配列の作成。Juliaでは
collect
関数を使う。
julia> b = collect(0:4)
5-element Array{Int64,1}:
0
1
2
3
4
- ステップを
0.2
にする。
これもcollect
を使います。Pythonと違ってSTEPを真ん中に書くとうまくいきました。
julia> c = collect(1:0.2:3)
11-element Array{Float64,1}:
1.0
1.2
1.4
1.6
1.8
2.0
2.2
2.4
2.6
2.8
3.0
ただし、3まで指定すると最後の3自身が入るようです(Pythonの例では2.8まで)。同じ結果にするにはcollect(1:0.2:2.8)
でしょうか。未満の書き方があるかはわかりませんでした。
- 型の確認
julia> typeof(a)
Array{Int64,1}
julia> typeof(c)
Array{Float64,1}
- 作成時に型を指定する。
julia> d = Float64[1, 2, 3]
3-element Array{Float64,1}:
1.0
2.0
3.0
julia> typeof(d)
Array{Float64,1}
- 引数に浮動小数点数を指定
julia> e = collect(0.:4.)
5-element Array{Float64,1}:
0.0
1.0
2.0
3.0
4.0
julia> typeof(e)
Array{Float64,1}
2次元配列
2次元配列の操作
julia> a = Float64[2 3 4; 5 6 7]
2×3 Array{Float64,2}:
2.0 3.0 4.0
5.0 6.0 7.0
- 第1行・第2列の要素
- 第2列の全ての要素
- 第2行の全ての要素
- 第1行の第3列以降
- 第1行の3列より前
julia> a[1, 2]
3.0
julia> a[:, 2]
2-element Array{Float64,1}:
3.0
6.0
julia> a[2, :]
3-element Array{Float64,1}:
5.0
6.0
7.0
julia> a[1, 3:end]
1-element Array{Float64,1}:
4.0
julia> a[1, 1:2]
2-element Array{Float64,1}:
2.0
3.0
最後の「第1行の3列より前」の書き方はわからず、インデックスの範囲指定にしました。
配列のデータ属性
- 3行5列の2次元配列に変換
julia> a = reshape(collect(0.:14.), 3, 5)
3×5 Array{Float64,2}:
0.0 3.0 6.0 9.0 12.0
1.0 4.0 7.0 10.0 13.0
2.0 5.0 8.0 11.0 14.0
※Pythonの行列表示とは転置状態になっています。
- 配列の形状
Pythonのshape
にあたる関数はsize
でいけました。
julia> size(a)
(3, 5)
- 配列の次元数
- 要素数。これは
size
でなくlength
でした。
julia> ndims(a)
2
julia> length(a)
15
- 1次元配列のまま
julia> b = collect(0.:3.)
4-element Array{Float64,1}:
0.0
1.0
2.0
3.0
julia> size(b)
(4,)
julia> ndims(b)
1
julia> length(b)
4
reshape関数と形状の変更
※本ではreshapeメソッドとなっていますが、Juliaでは関数の方があっていそうなので見出しは変更しました。
形状のいろいろな変更方法
julia> a = collect(0.:15.)
16-element Array{Float64,1}:
0.0
1.0
2.0
3.0
4.0
5.0
6.0
7.0
8.0
9.0
10.0
11.0
12.0
13.0
14.0
15.0
- 列数自動で形状の変更
julia> c = reshape(a, 4, :)
4×4 Array{Float64,2}:
0.0 4.0 8.0 12.0
1.0 5.0 9.0 13.0
2.0 6.0 10.0 14.0
3.0 7.0 11.0 15.0
- 1次元配列に戻す
julia> vec(c)
16-element Array{Float64,1}:
0.0
1.0
2.0
3.0
4.0
5.0
6.0
7.0
8.0
9.0
10.0
11.0
12.0
13.0
14.0
15.0
- 行数自動で形状の変更
- 列数自動で形状の変更
julia> b = collect(0.:3.)
4-element Array{Float64,1}:
0.0
1.0
2.0
3.0
julia> reshape(b, :, 1)
4×1 Array{Float64,2}:
0.0
1.0
2.0
3.0
julia> reshape(b, 1, :)
1×4 Array{Float64,2}:
0.0 1.0 2.0 3.0
Juliaでnp.newaxis
にあたるものはわかりませんでした。
その他の配列の操作
いろいろな配列の作成
- 要素が全て0である配列の作成
julia> a = zeros(3, 4)
3×4 Array{Float64,2}:
0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0
- 要素が全て1である配列の作成
julia> b = ones(2, 2)
2×2 Array{Float64,2}:
1.0 1.0
1.0 1.0
- 任意の要素を持つ配列の作成
np.empty
にあたるJuliaの関数は見当たらず・・・。
@tenfu2tea さんにご教示いただきました!
np.empty
にあたるJuliaの関数はBase.similar(Storagetype, axes)
ということです。
https://docs.julialang.org/en/v1.0/base/arrays/#Base.similar
マニュアル読みましたが引数の指定が難しいですね・・・。similar
なので似ているものを作ると言うことでしょうか。
本に近い形で作ろうとして下記のようになりました。
julia> similar(1:10, Float64, 2, 5)
2×5 Array{Float64,2}:
2.21031e-314 4.94066e-324 2.21031e-314 4.94066e-323 2.47033e-323
2.21031e-314 2.21031e-314 2.21031e-314 5.92879e-323 2.19521e-314
- 等差数列を要素として持つ配列の作成
linspace
はないみたいなので、range
で指定するようです。
こちらも、@tenfu2tea さんにご教示いただきました!
LinRange
で指定するとのことです。
https://docs.julialang.org/en/v1.0/base/collections/#Base.LinRange
range
で指定した方法とLinRange
で指定した方法を載せておきます。
- range
julia> collect(range(0., stop = 1., length = 10))
10-element Array{Float64,1}:
0.0
0.1111111111111111
0.2222222222222222
0.3333333333333333
0.4444444444444444
0.5555555555555556
0.6666666666666666
0.7777777777777778
0.8888888888888888
1.0
- LinRange
julia> collect(LinRange(0., 1., 10))
10-element Array{Float64,1}:
0.0
0.1111111111111111
0.2222222222222222
0.3333333333333333
0.4444444444444444
0.5555555555555556
0.6666666666666666
0.7777777777777778
0.8888888888888888
1.0
行列の連結
いろいろな行列の連結
- 2次元配列を2つ用意
julia> a = [0 1 2; 3 4 5]
2×3 Array{Int64,2}:
0 1 2
3 4 5
julia> b = [6 7 8; 9 10 11]
2×3 Array{Int64,2}:
6 7 8
9 10 11
- 縦方向に連結
julia> vcat(a, b)
4×3 Array{Int64,2}:
0 1 2
3 4 5
6 7 8
9 10 11
- 横方向に連結
julia> hcat(a, b)
2×6 Array{Int64,2}:
0 1 2 6 7 8
3 4 5 9 10 11
- さらに1次元配列を2つ用意
julia> c = collect(0:2)
3-element Array{Int64,1}:
0
1
2
julia> d = collect(3:5)
3-element Array{Int64,1}:
3
4
5
- 縦方向に連結と横方向に連結
julia> vcat(c, d)
6-element Array{Int64,1}:
0
1
2
3
4
5
julia> hcat(c, d)
3×2 Array{Int64,2}:
0 3
1 4
2 5
- 形状が合わないとエラー
julia> vcat(a, c)
ERROR: ArgumentError: number of columns of each array must match (got (3, 1))
Stacktrace:
[1] _typed_vcat(::Type{Int64}, ::Tuple{Array{Int64,2},Array{Int64,1}}) at ./abstractarray.jl:1283
[2] typed_vcat at ./abstractarray.jl:1297 [inlined]
[3] vcat(::Array{Int64,2}, ::Array{Int64,1}) at /Users/osx/buildbot/slave/package_osx64/build/usr/share/julia/stdlib/v1.0/SparseArrays/src/sparsevector.jl:1065
[4] top-level scope at none:0
- 2次元配列に変換してから連結
julia> vcat(a, reshape(c, 1, :))
3×3 Array{Int64,2}:
0 1 2
3 4 5
0 1 2