Julia 入門02 -- R と比較して（ベクトルと行列）

以下は，R 入門のために書かれた

https://www.jaysong.net/rprogramming/

を，Julia ではこんな風になるよということで書いたものである。

R の入門というページは多く存在する。

R に入門しようとしている人 ... Julia にしませんか？

# ベクトルを作ってみよう

R では，ベクトルを定義するときには，以下のように書きます。

```R 
a <- c(1, 2, 5, 9, 11)
```

Julia では，ベクトルは，カンマ（`,`）で区切って要素を列挙し，全体を `[ ]` で囲んで定義します。変数への代入には，等号（`=`）を使います。
`c` って何だろう？と思う必要もありませんね。

```Julia
a = [1, 2, 5, 9, 11]
```

実際に，Julia を使いながら，読んでいただくとよろしいかも知れません。

Julia をインストールした後，コマンドラインで

```Julia
$ julia
```

と入力すると，

```Julia
_
_       _ _(_)_     |  Documentation: https://docs.julialang.org
(_)     | (_) (_)    |
_ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
| | | | | | |/ _` |  |
| | |_| | | | (_| |  |  Version 1.6.2 (2021-07-14)
_/ |\__'_|_|_|\__'_|  |  Official https://julialang.org/ release
|__/                   |


julia>
```

のような表示になるでしょう。
最終行のプロンプト `julia>` の後にプログラムを入力すると，その評価結果が画面にプリントされます。Julia の対話環境でのプログラムは，この繰り返しです。
これを REPL(read-eval-print loop) と呼んでいます。

R のコンソールと同じです。

以下のように入力してみましょう。

```Julia
v = [2, 3, 5, 7, 11]
```

Julia が読み取り評価した結果は，以下のようになるでしょう。

```Julia
5-element Vector{Int64}:
  2
  3
  5
  7
 11
```
最初の行は v に代入されたものが，「5 個の要素（64ビット整数 Int64）を持つベクトル」であると解釈したことを表しています。

1 番目の要素を 2.0 と書いてみましょう。

```Julia
w = [2.0, 3, 5, 7, 11]
```

w は，「5 個の要素（64ビット実数 Float64）を持つベクトル」であると解釈されました。

```Julia
5-element Vector{Float64}:
  2.0
  3.0
  5.0
  7.0
 11.0
```

文字列を含むベクトルも作れます。要素は文字列型（String 型）です。

```Julia
fruits = ["apple", "banana", "orange"]
3-element Vector{String}:
 "apple"
 "banana"
 "orange"
```

Julia では，文字列は `" "` で囲みます。`' '` で囲んではいけません。
1 文字を `' '` でくくったものは，Char 型（文字列型ではなく文字型）です。

```Julia
characters = ['a', 'b', 'あ', '9', '@']
5-element Vector{Char}:
 'a': ASCII/Unicode U+0061 (category Ll: Letter, lowercase)
 'b': ASCII/Unicode U+0062 (category Ll: Letter, lowercase)
 'あ': Unicode U+3042 (category Lo: Letter, other)
 '9': ASCII/Unicode U+0039 (category Nd: Number, decimal digit)
 '@': ASCII/Unicode U+0040 (category Po: Punctuation, other)
```

#ベクトルの計算をしてみよう（四則演算+α）

##ベクトルと定数の計算をしてみよう

定数とベクトルの演算では `+`, `-`, `*`, `/`, `^` ではなく，`.+`, `.-`, `.*`, `./`, `.^` のように演算子の前に `.` を付けます。
`.^` は 羃乗です（R と同じですね）。

以下において，入力の結果を表示していない場合があります。結果が自明な場合もありますが，そうでない場合などには実際に入力してみるとよいでしょう。

```Julia
x = [2, 3, 5, 7, 11]
y1 = 2 .+ x
y2 = 20 .- x
y3 = 5 .* x
y4 = 100 ./ x
y5 = 2 .^ x
y6 = x .^ 3
```

今は，上に書かれたように覚えておくようにしましょう。
（たとえば，`5 .* x` は `5 * x` あるいは `5x` と書いても同じ結果になりますが，`100 ./ x` を `100 / x` と書くと，思いもよらない結果が得られます）

##ベクトルとベクトルの計算をしてみよう

Julia では 同じ長さのベクトル同士の演算だけが行えます。演算子の前に `.` を付けなければならないのはベクトルと定数の演算の場合と同じです。

```Julia
x = [2, 3, 5, 7, 11]
y = [1, 2, 4, 8, 16]
z1 = x .+ y
z2 = x .- y
z3 = x .* y
z4 = x ./ y
z5 = x .^ y
```

# 行列を作ってみよう

行列は二次元の配列です。定義は以下のようにします。

```Julia
a = [1 2 3
     4 5 6]
```

a は 以下のようになります。

```Julia
2×3 Matrix{Int64}:
 1  2  3
 4  5  6
```

定義と結果を見比べてみると一目瞭然ですが，行列の定義は，行ごとに空白で区切って要素を列挙します（カンマで区切ってはいけません）。
1 行目を書き終えればリターンキーを押して，2行目を書きます。ベクトルの定義のときと同じく，全体を `[ ]` で囲みます。

かならずしも行ごとに改行しなくても，行の終わりの印としてセミコロンを書いても構いません。しかし，書き間違いを避けるためにはなるべく桁をそろえて，行ごとに改行するほうがよいでしょう。

```Julia
b = [1.2 3.5 5.3 3.6; 2.2 5.8 4.5 2.4]
2×4 Matrix{Float64}:
 1.2  3.5  5.3  3.6
 2.2  5.8  4.5  2.4
```

##行列と定数の計算をしてみよう

定数と行列の演算では，R と同じく，定数と行列の各要素との演算が行われます。
演算子の前に `.` を付けるのはベクトルとの演算のときと同じです。

```Julia
x = [2 3 5 7 11
     1 2 4 8 16]
a1 = 2.3 .+ x
a2 = 3 .- x
a3 = 4 .* x
a4 = 100 ./ x
a5 = 1.2 .^ x
a6 = x .^ 3
```

#行列と行列の計算をしてみよう（四則演算）

四則演算は行列の要素同士で計算されます。したがって，行数と列数の同じ行列でなければいけません。

```Julia
x = [2 3 5 7 11
     1 2 4 8 16]
y = [1 2 3 4  5
     6 7 8 9 10]
b1 = x .+ y
b2 = x .- y
b3 = x .* y
b4 = x ./ y
b5 = x .^ y
b6 = y .^ x
```

#行列積（行列と行列の掛算）

m × n 行列と　n × k 行列の積は「行列積」であり，上で定義した行列の要素同士の掛算とは別物です。
演算子は `*` です（`.*` ではありません。ちなみに R では `%*%` ですね）。

以下の例で，v は 2 × 3 行列，w は 3 × 4 行列で，「m × n 行列と　n × k 行列」という条件を満たしています。
`v * w` は計算できますが，`w * v` は計算できません。

```Julia
v = [1 2 3
     2 3 4]
w = [2 4 5 6
     1 3 4 2
     3 3 1 6]
matrixmultiply = v * w
#=
2×4 Matrix{Int64}:
 13  19  16  28
 19  29  26  42
=#
```

#逆行列

逆行列は正方行列（n × n 行列）の場合に求められることがあります（求められないこともあるわけですが）。
a の逆行列は inv(a) で求めることが出来ます。

以下の表示において #= と =# で囲まれた部分は Julia でいえば注釈ですが，直前のプログラムの結果を表示するために使っています。

```Julia
a = [3 2 4
     4 1 5
     5 3 2]
b = inv(a)
#=
3×3 Matrix{Float64}:
 -0.565217   0.347826    0.26087
  0.73913   -0.608696    0.0434783
  0.304348   0.0434783  -0.217391
=#
```

逆行列と元の行列の行列積を計算すると(`a * b` でも `b * a` でも同じく)，単位行列（対角成分が 1，非対角成分が（計算誤差の範囲内で）0）になります。

```Julia
a * b
#=
3×3 Matrix{Float64}:
 1.0          1.11022e-16  -2.22045e-16
 0.0          1.0           0.0
 1.11022e-16  3.88578e-16   1.0
=#

b * a
#=
3×3 Matrix{Float64}:
  1.0          0.0   0.0
 -5.55112e-17  1.0  -1.11022e-16
 -2.22045e-16  0.0   1.0
=#
```

逆行列の応用先としては，多元連立方程式の解を求めるときに使われます。

3x + 2y + 4z = 3
4x +  y + 5z = 2
5x + 3y + 2z = 4

の左辺の係数行列が上の `a` です。
右辺のベクトルを

```Julia
c = [3, 2, 4]
```

として，

```Julia
b * c
#=
3-element Vector{Float64}:
 0.04347826086956541
 1.1739130434782608
 0.13043478260869568
=#
```

で解 `[x, y, z]` のベクトルが得られます。
なお，`b * c` において `b` は 3 × 3 行列，b は要素数 3 のベクトルですが，この場合 `b` は 3 x 1 行列と見なされ，行列積が計算されます。

Julia では 逆行列を使わずに `\` 演算子で解を求めることができます。というか，`\` 演算子を使うように強く勧められています。

```Julia
a \ c
#=
3-element Vector{Float64}:
 0.04347826086956523
 1.1739130434782608
 0.13043478260869568
=#
```
`b * c` と `a \ c` で，結果が少し違うことがあります。 `a \ c` のほうが計算精度が高いためにこのようなことが起こりえます。

おまけ　`\` という演算子と `inv()` という関数の関係。

スカラーでは，たとえば
`inv(5)` は 5 の逆数 1/5 つまり 0.2 です。
「5 の逆数に 3 をかける」というのは，`inv(5) * 3` で，`0.2 * 3` ですから，0.6 ですね。
`\` を使うと「5 の逆数に 3 をかける」は `5 \ 3` と書きます。
結果は `5 \ 3 = 0.6` になります。逆数をとっていません（もちろん，計算機内部では**ちゃんと**逆数をとって計算していますが。この，**ちゃんと**というところが肝腎です。つまり，逆行列を求めて行列積を計算するということではなく，計算精度を十分に考慮した計算方法を採用しているということです。）

# ベクトルの要素を参照してみよう

以下の記述で，`#` で始まる行は注釈行です。R と同じですね。
計算結果を表示するためにも使っています。
プログラムを実行してみるときには `#` の直前までだけを入力（コピーペースト）してください。

```Julia
x = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0];

# 1 つの要素を参照。添え字を 1 個で指定する。最初の要素の添え字は 1。
a1 = x[3]   # 3.0

# 連続する要素を参照。添え字を : で繋いで指定する。
a2 = x[5:8] # ベクトル [5.0, 6.0, 7.0, 8.0]

# 任意の要素を参照。添え字をベクトル（次の例では[2, 3, 5, 7]）として指定する。
a3 = x[[2, 3, 5, 7]] # ベクトル [2.0, 3.0, 5.0, 7.0]

# 特別に，end という添え字は，最後の要素を参照する。
a4 = x[end] # 10.0

# 最後から 5 番目から最後から 2 番目の要素を参照する。
a5 = x[end-4:end-2] # ベクトル [6.0, 7.0, 8.0]
```

代入の場合（左辺で使用する）も同じです。
注意すべき点として，2 番目のような場合には代入先と代入元が同じ数であれば代入記号は `=` でよいのですが，3 番目のような場合は `.=` としなければエラーになります。

```Julia
x = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0];
x[5] = 7
x[7:9] = [1, 2, 3]
x[1:3] .= 0
# 代入後の結果は以下のようになる（println() はカッコの中の物を表示（プリント）する関数）
println(x) # [0.0, 0.0, 0.0, 4.0, 7.0, 6.0, 1.0, 2.0, 3.0, 10.0]
```

# 行列の要素を参照してみよう

行列（二次元配列）の場合は，要素を指定する 2 つの添え字をカンマで区切るだけで，ベクトル要素の指定と同じです。

```Julia
x = [2.0 3.0 5.0 7.0 11.0
     1.0 2.0 4.0 8.0 16.0];
# 1 つの要素
x[1, 3] # 5.0

# 1 行目（全ての列 : で表す）
x[1, :] # [2.0 3.0 5.0 7.0 11.0]

# 3 列目（全ての行 : で表す）
x[:, 3] # [5.0, 4.0]

# 4，5列（全ての行 : で表す）
x[:, 4:5]
#=
2×2 Matrix{Float64}:
 7.0  11.0
 8.0  16.0
=#
```

代入の場合も，ベクトル要素への代入と同じです。