はじめに
Juliaにおける基本的な操作を書き残します.
間違い等ありましたら, ぜひご連絡ください.
ちなみにJulia(ver1.1.0)における環境で動作チェックしています.
それと行列操作に関する逆引き的なものを用意しようと思っているのでそちらもよろしくお願いします.
(作成中...)
行列の定義
単純な書き方
行の区切りは改行
もしくは;
で表現し, 列の区切りは
(半角スペース)で表現する.
つまり, 以下のようにすれば作成できる.
julia> mat = [1 2 3; 4 5 6]
2×3 Array{Int64,2}:
1 2 3
4 5 6
julia> mat = [
1 2 3
4 5 6
]
2×3 Array{Int64,2}:
1 2 3
4 5 6
内包表記で生成する
内包表記というものを利用しても, 行列は作成できる.
# 内包表記
julia> mat = [ x for x in 1:4]
4-element Array{Int64,1}:
1
2
3
4
# 内包表記を二重で利用する
julia> mat = [ 10a + b for a in 0:2, b in 0:3]
3×4 Array{Int64,2}:
0 1 2 3
10 11 12 13
20 21 22 23
後置ifを利用した内包表記
julia> mat = [ i for i in 0:10 if (i%2)==0 ]
6-element Array{Int64,1}:
0
2
4
6
8
10
また2次元行列を作成する時に後置ifを利用すると, ベクトルになって返ってくる.
(実際後置ifを利用すると次元数がバラバラになる可能性があるので, 行列が作れてしまうといろいろと問題があるけど.)
julia> mat = [ a + b for a in 1:2, b in 1:2 ]
2×2 Array{Int64,2}:
2 3
3 4
julia> mat = [ a + b for a in 1:2, b in 1:2 if true ]
4-element Array{Int64,1}:
2
3
3
4
そのため, 2次元以上で後置ifを利用する場合は, 3項演算子等を利用して違う数字を埋めるようにすれば大丈夫.
julia> mat = [ ( (b%2==a%2) ? 10a + b : 0 ) for a in 0:1, b in 0:9 ]
2×10 Array{Int64,2}:
0 0 2 0 4 0 6 0 8 0
0 11 0 13 0 15 0 17 0 19
関数を使った行列の生成
零行列を作成する
組み込みの関数であるzeros([T=Float64,] dims...)
を利用していきます.
引数 | 概要 |
---|---|
T |
型を指定します. 省略可. |
dims... |
次元数を列挙します. |
julia> zeros(ComplexF64, 2, 2)
2×2 Array{Complex{Float64},2}:
0.0+0.0im 0.0+0.0im
0.0+0.0im 0.0+0.0im
julia> zeros(Int8, 2, 2, 2)
2×2×2 Array{Int8,3}:
[:, :, 1] =
0 0
0 0
[:, :, 2] =
0 0
0 0
julia> zeros(2, 3)
2×3 Array{Float64,2}:
0.0 0.0 0.0
0.0 0.0 0.0
すべての要素が1の行列
組み込みの関数であるones([T=Float64,] dims...)
を利用していきます.
利用の仕方は上記のzeros
と同じなので省略します.
単位行列
単位行列の生成方法はバージョンによって結構変わってきます.
(eye
だったり,I
を利用したり...)
ver1.0以降(自分の場合はver1.1.0
)においてはLinearAlgebra
にあるI
を利用して単位行列を作成します.
構文としてはMatrix{T}(I, row, col}
です.
ちなみに正則行列でなくても作成できます.
julia> using LinearAlgebra
julia> Matrix{Int8}(I, 3, 3)
3×3 Array{Int8,2}:
1 0 0
0 1 0
0 0 1
julia> Matrix{ComplexF64}(I, 3, 3)
3×3 Array{Complex{Float64},2}:
1.0+0.0im 0.0+0.0im 0.0+0.0im
0.0+0.0im 1.0+0.0im 0.0+0.0im
0.0+0.0im 0.0+0.0im 1.0+0.0im
julia> Matrix{Int8}(I, 4, 3)
4×3 Array{Int8,2}:
1 0 0
0 1 0
0 0 1
0 0 0
ランダムな値を持つ行列を生成
組み込み関数であるrand([rng=GLOBAL_RNG], [S], [dims...])
を利用していきます.
引数 | 概要 | 省略 | 注意 |
---|---|---|---|
rng |
わからないです (たぶんシード値?) |
可 | わかる方は教えてください |
S |
生成するデータの指定 (指定方法は後述) |
可 | tupleで指定できるのはv1.1 以降から |
dims |
各次元数 | 可 |
S
の指定方法は結構柔軟で, 以下に示すような方法で指定できます.
指定方法 | データの選ばれ方 |
---|---|
indexable collection ( 1:9 , (1, 2, 3, 100) など) |
そのタプルに属する値のうち1つ |
AbstractDict, AbstractSet | 〃 |
string | 文字列を文字単位に分解したうちの1つ. |
type |
typemin(S) 〜typemax(S) のうちの1つ |
以下にそれぞれの実行例を載せておきます.
julia> rand((1, 2, 3, -99), 2, 9)
2×9 Array{Int64,2}:
2 3 1 2 -99 3 2 2 3
2 -99 3 -99 2 -99 2 -99 -99
julia> rand(Dict("bird"=>3, "mammal"=>345, "reptiles"=>32), 2, 4)
2×4 Array{Pair{String,Int64},2}:
"mammal"=>345 "mammal"=>345 "reptiles"=>32 "bird"=>3
"reptiles"=>32 "bird"=>3 "bird"=>3 "reptiles"=>32
julia> rand("hoge", 2, 9)
2×9 Array{Char,2}:
'e' 'o' 'h' 'g' 'o' 'o' 'o' 'e' 'e'
'o' 'h' 'h' 'e' 'e' 'h' 'e' 'e' 'h'
julia> rand("aaaaaaaaaaag", 2, 9)
2×9 Array{Char,2}:
'a' 'a' 'a' 'a' 'a' 'a' 'g' 'a' 'a'
'a' 'a' 'a' 'a' 'a' 'a' 'a' 'g' 'a'
julia> rand(Char, 2, 6)
2×6 Array{Char,2}:
'\Ub8de6' '𗀋' '骊' '\U63ebc' '\Ue15e4' '\U640aa'
'\U39ad9' '㵑' '\U4d6b0' '뛐' '\U6302d' '\U8d876'
julia> rand(ComplexF64, 3, 3)
3×3 Array{Complex{Float64},2}:
0.833554+0.844678im 0.0205492+0.966243im 0.665147+0.809684im
0.237675+0.252522im 0.30283+0.414608im 0.139303+0.571629im
0.386357+0.949509im 0.56883+0.772397im 0.984182+0.255435im
標準正規分布に従う乱数を持つ行列を生成
randn([rng=GLOBAL_RNG], [T=Float64], [dims...])
を利用します.
使い方はrand
とほぼ同じなので, 省略します.
またrandexp
も, もちろんあります.
添字
Juliaの添字は1から始まるので注意が必要です.
添字の選択方法に関しては以下の二通ります(たぶん).
各要素を一様の数字で選択する
こんな感じ.
julia> mat = [ 3a + b for a in 0:2, b in 1:3]
3×3 Array{Int64,2}:
1 2 3
4 5 6
7 8 9
julia> print(mat[1], " ", mat[4], " ", mat[7], "\n",
mat[2], " ", mat[5], " ", mat[8], "\n",
mat[3], " ", mat[6], " ", mat[9], "\n")
1 2 3
4 5 6
7 8 9
mat[行, 列]形式で選択する
こんな感じ.
julia> mat = [ 3a + b for a in 0:2, b in 1:3]
3×3 Array{Int64,2}:
1 2 3
4 5 6
7 8 9
julia> print(mat[1, 1], " ", mat[1, 2], " ", mat[1, 3], "\n",
mat[2, 1], " ", mat[2, 2], " ", mat[2, 3], "\n",
mat[3, 1], " ", mat[3, 2], " ", mat[3, 3], "\n")
1 2 3
4 5 6
7 8 9
行/列の切り出し
Juliaでは次元数を保持せずに特定行/列を取ってくることができます.
# 1行目をとる
julia> mat[1, :]
3-element Array{Int64,1}:
1
2
3
# 1列目をとる
julia> mat[:, 1]
3-element Array{Int64,1}:
1
4
7
複数行/複数列の切り出し
julia> mat[1:2, :]
2×3 Array{Int64,2}:
1 2 3
4 5 6
julia> mat[:, 1:2]
3×2 Array{Int64,2}:
1 2
4 5
7 8
部分切り出し
julia> mat[2:3, 2]
2-element Array{Int64,1}:
5
8
julia> mat[2:3, 1:2]
2×2 Array{Int64,2}:
4 5
7 8
基本演算
行列演算と要素毎の演算のそれぞれについて触れていきます.
要素毎の演算
.
で各関数を各要素に適用できます.
julia> a = [1 2 3; 4 5 6; 7 8 9]
3×3 Array{Int64,2}:
1 2 3
4 5 6
7 8 9
julia> b = [-1 -2 -3; 4 5 6; -7 -8 -9]
3×3 Array{Int64,2}:
-1 -2 -3
4 5 6
-7 -8 -9
# 算術演算子
julia> a .* b
3×3 Array{Int64,2}:
-1 -4 -9
16 25 36
-49 -64 -81
julia> a .*= b
3×3 Array{Int64,2}:
-1 -4 -9
16 25 36
-49 -64 -81
算術演算子以外にも利用できます. また, 自作関数にも適用することができます.
# 関数
julia> a = [1 2 3; 4 5 6; 7 8 9]
3×3 Array{Int64,2}:
1 2 3
4 5 6
7 8 9
julia> sin.(a)
3×3 Array{Float64,2}:
0.841471 0.909297 0.14112
-0.756802 -0.958924 -0.279415
0.656987 0.989358 0.412118
julia> myfunc = function(x) 2x -5 end
#5 (generic function with 1 method)
julia> myfunc.(a)
3×3 Array{Int64,2}:
-3 -1 1
3 5 7
9 11 13
一応, map
関数を利用してでも似たようなことが実現できます.
a = map(sin, a)
a = map(myfunc, a)
要素毎の代入
=
を用いた通常の代入ではなく, .=
を用いることで要素毎に代入することができます.
julia> mat = [ 3a + b for a in 0:2, b in 1:3]
3×3 Array{Int64,2}:
1 2 3
4 5 6
7 8 9
julia> mat .= -1
3×3 Array{Int64,2}:
-1 -1 -1
-1 -1 -1
-1 -1 -1
和算, 減算
演算子+
, -
を利用していきます.
julia> a = [1 2 3; 4 5 6; 7 8 9]
3×3 Array{Int64,2}:
1 2 3
4 5 6
7 8 9
julia> b = [-1 -2 -3; 4 5 6; -7 -8 -9]
3×3 Array{Int64,2}:
-1 -2 -3
4 5 6
-7 -8 -9
julia> a + b
3×3 Array{Int64,2}:
0 0 0
8 10 12
0 0 0
julia> a - b
3×3 Array{Int64,2}:
2 4 6
0 0 0
14 16 18
積
行列の積は*
, 要素毎の掛け算は.*
となります.s
julia> a * b
3×3 Array{Int64,2}:
-14 -16 -18
-26 -31 -36
-38 -46 -54
julia> a .* b
3×3 Array{Int64,2}:
-1 -4 -9
16 25 36
-49 -64 -81
割り算, 逆行列の掛け算
要素毎の割り算は./
を使います.
julia> a ./ b
3×3 Array{Float64,2}:
-1.0 -1.0 -1.0
1.0 1.0 1.0
-1.0 -1.0 -1.0
演算子/
は少し特殊で, a / b
はa * inv(b)
を表します.
julia> x = randn(Float64, 3, 3)
3×3 Array{Float64,2}:
0.774262 -0.385865 -1.1918
0.402656 -1.53214 1.95856
-0.622096 0.619093 -0.787436
julia> y = randn(Float64, 3, 3)
3×3 Array{Float64,2}:
0.330775 -0.95705 0.993989
-1.37908 -0.312028 0.0130837
0.882019 0.93005 0.816249
julia> x / y
3×3 Array{Float64,2}:
-0.254909 -1.34409 -1.12813
1.75524 0.293593 0.257316
-0.763695 0.243228 -0.0386082
julia> x * inv(y)
3×3 Array{Float64,2}:
-0.254909 -1.34409 -1.12813
1.75524 0.293593 0.257316
-0.763695 0.243228 -0.0386082
また\
では, a \ b
はinv(a) * b
を表します.
julia> x \ y
3×3 Array{Float64,2}:
-0.712879 -1.7516 -1.79956
-0.165542 -0.484339 -2.15161
-0.687072 -0.178097 -1.30651
julia> inv(x) * y
3×3 Array{Float64,2}:
-0.712879 -1.7516 -1.79956
-0.165542 -0.484339 -2.15161
-0.687072 -0.178097 -1.30651
逆行列
inv(x)
を利用します.
転置行列
'
を利用してx'
のように書きます.
ちなみに複素数にx'
を利用するとエルミート行列になってしまうため, transpose()
を使いましょう.
julia> mat = [1 2 3; 4 5 6; 7 8 9]
3×3 Array{Int64,2}:
1 2 3
4 5 6
7 8 9
julia> mat'
3×3 LinearAlgebra.Adjoint{Int64,Array{Int64,2}}:
1 4 7
2 5 8
3 6 9
julia> mat = rand(Complex{Int8}, 2, 2)
2×2 Array{Complex{Int8},2}:
13+19im 7+92im
82-10im 91+53im
# エルミート行列になっちゃう
julia> mat'
2×2 LinearAlgebra.Adjoint{Complex{Int8},Array{Complex{Int8},2}}:
13-19im 82+10im
7-92im 91-53im
# 複素数の転置はこちらを使う
julia> transpose(mat)
2×2 LinearAlgebra.Transpose{Complex{Int8},Array{Complex{Int8},2}}:
13+19im 82-10im
7+92im 91+53im
エルミート行列(共役転置行列, 自己随伴行列)
前節で説明したように, 複素数に対して'
を利用するとエルミート行列が得られます.
julia> mat = rand(Complex{Int8}, 2, 2)
2×2 Array{Complex{Int8},2}:
13+19im 7+92im
82-10im 91+53im
# エルミート行列
julia> mat'
2×2 LinearAlgebra.Adjoint{Complex{Int8},Array{Complex{Int8},2}}:
13-19im 82+10im
7-92im 91-53im
# 複素数の通常の転置はこちらを使う
julia> transpose(mat)
2×2 LinearAlgebra.Transpose{Complex{Int8},Array{Complex{Int8},2}}:
13+19im 82-10im
7+92im 91+53im
固有値, 固有ベクトル
LinearAlgebra
のeigvals
, eigvecs
を利用していきます.
それぞれ固有値, 固有ベクトルを得ることができます.
julia> using LinearAlgebra
julia> a = [1 2; 3 4]
2×2 Array{Int64,2}:
1 2
3 4
julia> eigvals(a)
2-element Array{Float64,1}:
-0.3722813232690143
5.372281323269014
julia> eigvecs(a)
2×2 Array{Float64,2}:
-0.824565 -0.415974
0.565767 -0.909377
次元数1の箇所を削る
dropdims
を利用していきます.
削れるのは次元数が1の箇所のみです.
julia> a = rand(1, 1, 1, 3)
1×1×1×3 Array{Float64,4}:
[:, :, 1, 1] =
0.4319242309225346
[:, :, 1, 2] =
0.22722643863542324
[:, :, 1, 3] =
0.7460652772993
julia> dropdims(a, dims=(2, 3))
1×3 Array{Float64,2}:
0.431924 0.227226 0.746065
julia> dropdims(a, dims=(1, 2, 3))
3-element Array{Float64,1}:
0.4319242309225346
0.22722643863542324
0.7460652772993
配列の複製
他の言語でもそうですがふつーにb = a
をしてbにaをコピーすると
julia> a = [1 2 3; 4 5 6; 7 8 9]
3×3 Array{Int64,2}:
1 2 3
4 5 6
7 8 9
julia> b = a
3×3 Array{Int64,2}:
1 2 3
4 5 6
7 8 9
julia> b .= 0
3×3 Array{Int64,2}:
0 0 0
0 0 0
0 0 0
julia> a
3×3 Array{Int64,2}:
0 0 0
0 0 0
0 0 0
のように, 値だけでなく参照先まで同じになってしまう.(浅いコピー)
そこで, 値だけを得たい場合はcopy()
を利用する.(深いコピー)
julia> a = [1 2 3; 4 5 6; 7 8 9]
3×3 Array{Int64,2}:
1 2 3
4 5 6
7 8 9
julia> b = copy(a)
3×3 Array{Int64,2}:
1 2 3
4 5 6
7 8 9
julia> b .= 0
3×3 Array{Int64,2}:
0 0 0
0 0 0
0 0 0
julia> a
3×3 Array{Int64,2}:
1 2 3
4 5 6
7 8 9
複素数の演算
実部をとる
ビルトイン関数のreal()
を使っていきます.
julia> real(1.2 + 3.4im)
1.2
julia> real(-2.5 + 2.1im)
-2.5
虚部をとる
ビルトイン関数のimag()
を使っていきます.
julia> imag(1.2 + 3.4im)
3.4
julia> imag(2.1 - 3.2im)
-3.2
複素共役をとる
ビルトイン関数のconj()
を使っていきます.
julia> conj(1.2 + 3.4im)
1.2 - 3.4im
julia> conj(1.2 - 3.4im)
1.2 + 3.4im
さいごに
その他についても思いつき次第追加していきたいと思います.