LoginSignup
20
19

More than 3 years have passed since last update.

Juliaにおける基本的な行列操作

Last updated at Posted at 2019-05-08

はじめに

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 / ba * 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 \ binv(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

固有値, 固有ベクトル

LinearAlgebraeigvals, 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

さいごに

その他についても思いつき次第追加していきたいと思います.

20
19
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
19