Julia 入門04 -- R と比較して（関数，制御コードなど）

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

https://ai-trend.jp/programming/r-beginner/r-beginner/

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

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

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

---

# Julia 言語の便利な関数

前にも使ったデータフレーム df を用いて説明する。

```julia
using DataFrames

df = DataFrame(
  id=[101, 106, 132, 145, 173],
  height=[175.3, 167.2, 173.1, 178.5, 168.7],
  weight=[73.2, 79.1, 65.6, 90.4, 66.2],
  bloodtype=["A", "B", "O", "A", "AB"]
  )

```




<table class="data-frame"><thead><tr><th></th><th>id</th><th>height</th><th>weight</th><th>bloodtype</th></tr><tr><th></th><th>Int64</th><th>Float64</th><th>Float64</th><th>String</th></tr></thead><tbody><p>5 rows × 4 columns</p><tr><th>1</th><td>101</td><td>175.3</td><td>73.2</td><td>A</td></tr><tr><th>2</th><td>106</td><td>167.2</td><td>79.1</td><td>B</td></tr><tr><th>3</th><td>132</td><td>173.1</td><td>65.6</td><td>O</td></tr><tr><th>4</th><td>145</td><td>178.5</td><td>90.4</td><td>A</td></tr><tr><th>5</th><td>173</td><td>168.7</td><td>66.2</td><td>AB</td></tr></tbody></table>



## データフレームの行数，列数をカウントする関数 `size()`

`size(データフレーム)`により，行数と列数を要素とするタプルを返す。


```julia
size(df)
```




    (5, 4)



## 参照したい列をベクトルとして取り出す

`データフレーム.列名` で取り出せる。


```julia
df.height
```




    5-element Vector{Float64}:
     175.3
     167.2
     173.1
     178.5
     168.7



ベクトルとして取り出した変数を用いて計算し，新たな列を作ることもできる。


```julia
df.BMI = df.weight ./ (df.height ./ 100) .^ 2
```




    5-element Vector{Float64}:
     23.820301209661277
     28.294624665186237
     21.893223146343182
     28.372133166992292
     23.260970165170463




```julia
df.obesity = df.BMI .>= 25
```




    5-element BitVector:
     0
     1
     0
     1
     0



## 要素の数をカウントするコマンド `freqency()`

ある変数（データフレームの列）の度数分布を求める。
使用するためには，`using FreqTables` が必要である。


```julia
using FreqTables
freqtable(df.bloodtype)
```




    4-element Named Vector{Int64}
    Dim1  │ 
    ──────┼──
    A     │ 2
    AB    │ 1
    B     │ 1
    O     │ 1



2 変数を指定するとクロス集計表を作成できる。

上で作成した `BMI` が 25 より大きいか小さいか `df.obesity` と血液型のクロス集計をしてみる（無意味であるが）。


```julia
freqtable(df.obesity, df.bloodtype)
```




    2×4 Named Matrix{Int64}
    Dim1 ╲ Dim2 │  A  AB   B   O
    ────────────┼───────────────
    false       │  1   1   0   1
    true        │  1   0   1   0



## 列名を見る関数 `names()`

`names(データフレーム)` でデータフレームの列名（変数名）を得ることができる。


```julia
names(df)
```




    6-element Vector{Symbol}:
     :id
     :height
     :weight
     :bloodtype
     :BMI
     :obesity



列を選択するとき `df.id` のように指定できると書いたが，それは `df[:id]` と同じである。
複数の列を選択するときは後者の書き方の拡張で，`df[[:id, :bloodtype]]` のように指定する。
つまり，変数名は先頭の `:` を含んだもの(Symbol)である。

Juliia では，データフレームに行名はない。1から始まる通し番号で識別する。


## 規則性のあるベクトルの生成

### ゼロベクトル`zeros()`, `falses()`

要素数を指定して，全ての要素が 0 のベクトルを生成する。整数ベクトル，実数ベクトル指定することもできる。デフォルトは実数ベクトルである。

`falses()` は要素が全て 0 のビットベクトルである。


```julia
zeros(5) # zeros(Float64, 5) と同じ
```




    5-element Vector{Float64}:
     0.0
     0.0
     0.0
     0.0
     0.0




```julia
zeros(Int, 5)
```




    5-element Vector{Int64}:
     0
     0
     0
     0
     0




```julia
falses(5)
```




    5-element BitVector:
     0
     0
     0
     0
     0



### 1 ベクトル `ones()`, `trues()`

要素数を指定して，全ての要素が 1 のベクトルを生成する。整数ベクトル，実数ベクトル指定することもできる。デフォルトは実数ベクトルである。

`trues()`は要素が全て 1 のビットベクトルである。


```julia
ones(5) # ones(Float64, 5) と同じ
```




    5-element Vector{Float64}:
     1.0
     1.0
     1.0
     1.0
     1.0




```julia
ones(Int, 5)
```




    5-element Vector{Int64}:
     1
     1
     1
     1
     1




```julia
trues(5)
```




    5-element BitVector:
     1
     1
     1
     1
     1



### 任意の要素を繰り返す `fill(値, 個数)`

指定した `値` を指定した `個数` だけ持つベクトルを生成する。


```julia
fill("any", 5)
```




    5-element Vector{String}:
     "any"
     "any"
     "any"
     "any"
     "any"




```julia
fill(1, 5) # ones(Int, 5) と同じ
```




    5-element Vector{Int64}:
     1
     1
     1
     1
     1




```julia
fill(true, 5) # Bool 型。trues(5) は BitVector 型
```




    5-element Vector{Bool}:
     1
     1
     1
     1
     1




```julia
fill(true, 5) .== trues(5) # 値としては同じ
```




    5-element BitVector:
     1
     1
     1
     1
     1




```julia
Base.summarysize(trues(5)) # メモリの使用量が違う
```




    72




```julia
Base.summarysize(fill(true, 5)) # メモリの使用量が違う
```




    45



### 等差ベクトル　初項:最終項 または 初項:公差:最終項

`初項:最終項` は公差が 1 のときの省略形で `初項:1:最終項` と同じである。
これによって作られるのはイテレータと呼ばれるもので，実際に数列ベクトルとして得るには `collect(初項:公差:最終項)` のようにする。


```julia
a = 1:5
```




    1:5




```julia
b = collect(1:5)
```




    5-element Vector{Int64}:
     1
     2
     3
     4
     5




```julia
a .== b
```




    5-element BitVector:
     1
     1
     1
     1
     1



## 変数の型の変換（数値化 parse()，文字列化 string()）

文字列を数値に変換するのは `parse()` だ，ベクトルを対象にするときは `parse.()`とする。整数に変換するときには第 1 引数を `Int`，実数に変換するときには `Float64` に指定する。


```julia
parse(Int, "12345") # 小数点を含んではいけない
```




    12345




```julia
parse(Float64, "12345") # 小数点はなくてもかまわない
```




    12345.0




```julia
parse.(Int, ["12", "345", "6789"])
```




    3-element Vector{Int64}:
       12
      345
     6789




```julia
parse.(Float64, ["3.14", "-1000", "0.0012"])
```




    3-element Vector{Float64}:
         3.14
     -1000.0
         0.0012



数値を文字列に変換するのは `string()` である。ベクトルを対象にするときは `string.()` とする。ベクトルに整数と実数が混ざっていると，すべて実数として（小数点を付けて）文字列に変換される。


```julia
string(12345)
```




    "12345"




```julia
string(54.67)
```




    "54.67"




```julia
string.([12, 3.45, -32.8, true, false])
```




    5-element Vector{String}:
     "12.0"
     "3.45"
     "-32.8"
     "1.0"
     "0.0"




```julia
string.([12, true, false])
```




    3-element Vector{String}:
     "12"
     "1"
     "0"



## 変数の型の確認 typeof()

変数（オブジェクト）の型は `typeof()` で調べることができる。


```julia
typeof(123)
```




    Int64




```julia
typeof(123.0)
```




    Float64




```julia
typeof(df)
```




    DataFrame




```julia
typeof(df.bloodtype)
```




    Vector{String} (alias for Array{String, 1})




```julia
typeof(false) == Bool
```




    true



## 欠損値関連

Julia では，欠損値は `missing` で表す。

### 欠損値かどうかを調べる関数 ismissing()

ベクトルを対象にするときは `missing.()` とする。`missing()` では，個別の値の検査は行われない。


```julia
ismissing(missing)
```




    true




```julia
ismissing.([1, 2, missing, 5, 9, missing, missing])
```




    7-element BitVector:
     0
     0
     1
     0
     0
     1
     1




```julia
ismissing.([1, 2, missing, 5, 9, missing, missing]) # 1 個の結果 false
```




    7-element BitVector:
     0
     0
     1
     0
     0
     1
     1




```julia
## ベクトルの長さ（要素数）を調べる関数 `length()`
```


```julia
length([1, 2, 3])
```




    3



## ユニークな要素を得る関数 `unique()`


```julia
x = [1, 2, 4, 6, 2 ,1, 3, 6]
unique(x)
```




    5-element Vector{Int64}:
     1
     2
     4
     6
     3



Set() でも同じような結果が得られるが，型は「集合」である。


```julia
Set(x)
```




    Set{Int64} with 5 elements:
      4
      6
      2
      3
      1



## 集合

Julia では，集合は「集合型」として定義されている。要素の格納順序は不定である（昇順でも降順でもない）。

### 集合の定義 Set()


```julia
a = Set([2 3 5 7 11 13 17 23]) # 素数
```




    Set{Int64} with 8 elements:
      5
      13
      7
      2
      11
      17
      3
      23




```julia
b = collect(1:10)
```




    10-element Vector{Int64}:
      1
      2
      3
      4
      5
      6
      7
      8
      9
     10



### 和集合 `union()`, `union!()`

複数の集合の和集合を求める関数は `union()` である。

`union!(a, b)` のような場合，結果は `a` に格納されるので，元の `a` が書き換えられては困るというような場合には `result = union(a, b)` のようにする。


```julia
union(a, b)
```




    Set{Int64} with 14 elements:
      5
      7
      8
      17
      23
      1
      13
      4
      6
      2
      11
      10
      9
      3




```julia
sort([i for i in union(a, b)]) # 集合を並べ替えるのは sort(union(a, b)) ではできない
```




    14-element Vector{Int64}:
      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     13
     17
     23



### 差集合 setdiff(), setdiff!()

`setdiff!(a, b)` のような場合，結果は `a` に格納されるので，元の `a` が書き換えられては困るというような場合には `result = setdiff(a, b)` のようにする。


```julia
setdiff(a, b)
```




    Set{Int64} with 4 elements:
      13
      11
      17
      23




```julia
setdiff(b, a)
```




    6-element Vector{Int64}:
      1
      4
      6
      8
      9
     10



### 積集合 intersect(), intersect!()

`intersect!(a, b)` のような場合，結果は `a` に格納されるので，元の `a` が書き換えられては困るというような場合には `result = intersect(a, b)` のようにする。


```julia
intersect(a, b)
```




    Set{Int64} with 4 elements:
      5
      7
      2
      3



## 繰り返しの `for` 文

以下のような `for - end` の組み合わせで，処理を繰り返すことを記述する。

```Julia
for 変数 in イテレータ
    繰り返される処理
end
```


```julia
for i in 1:5
    println(i*2)
end
```

    2
    4
    6
    8
    10


上の for - end の例は，`i` を 1 から 5 まで変えて，その都度 `i*2` を表示する（`println`) ということを表している。

1:5 の部分がイテレータで，ここでは 「1 から 5」を示しており，変数 `i` が 「1 から 5」に含まれていれば(`in`) ということを表している。

別の書き方では，`for i = 1:5` とすることもできる。このほうが「`i` を 1 から 5 まで変えて」ということに近いかも知れない。

## 条件によって処理を分岐する `if` 文

単独で使われる `if` 文は次のように記述される。

```Julia
    if 条件式
        条件式が true の場合に実行される処理
    end
```

条件式はその結果が論理値の真/偽（`true`/`false`) のいずれかを返すものである。たとえば `a < b` や `typeof(x) == Int` などである。

条件式が `true` の場合には `if - end` に挟まれた部分が実行される。処理は複数行で記述されることもある。

条件式が `false` の場合には何も実行されない（`end` の次の行へ移る）。




```julia
x = 3
if isodd(x)
    x = x * 2 + 1
end
println(x)
```

    7


条件式が `true` の場合の処理のほかに，`false` の場合には別の処理を行うというような場合には，`if - else - end` のように記述する。

```Julia
    if 条件式
        条件式が true の場合に実行される処理
    else
        条件式が false の場合に実行される処理
    end
```


```julia
x = 8
if isodd(x)
    x = x * 2 + 1
else
    x = x ÷ 2
end
println(x)
```

    4


条件式が複数あり，それぞれの条件式が `true` の場合の処理を行うというような場合には，`if - elseif - end` のように記述する。

```Julia
    if 条件式1
        条件式1が true の場合に実行される処理
    elseif 条件式2
        条件式2が true の場合に実行される処理
    elseif 条件式3
        条件式3が true の場合に実行される処理
    :
    end
```
elseif はいくつあってもかまわない。


```julia
score = 30
if x >= 80
    println("grade A")
elseif x >= 70
    println("grade B")
elseif x >= 60
    println("grade C")
elseif x >= 0
    println("grade D")
end
```

    grade D


上の例では 全ての条件式が `false` の場合にはなにも実行されない。もし `score` が 0 以上 100 以下であることがわかっているならば，最後の`elseif x >= 0` は，「それまでの条件式以外の場合」という意味の `else` に置き換えることができる。

すなわち，以下のように記述できる。

```Julia
    if 条件式1
        条件式1が true の場合に実行される処理
    elseif 条件式2
        条件式2が true の場合に実行される処理
    elseif 条件式3
        条件式3が true の場合に実行される処理
    :
    else
        以上のいずれの条件式も false の場合に実行される処理
    end
```


```julia
score = 30
if x >= 80
    println("grade A")
elseif x >= 70
    println("grade B")
elseif x >= 60
    println("grade C")
else
    println("grade D")
end
```

    grade D


## 統計関数

### 一変数統計関数 `mean()`, `var()`, `std()`, `median()`, `sum()`, `maximun()`, `minimum()`

Julia では，`mean()` などもそのままでは使えない（不便だ）。事前に `using Statistics` としておかねばならない。

また，最小値，最大値は多くのプログラミング言語では `min()`, `max()` だが，Julia では `maximun()`, `minimum()` である。


```julia
using Statistics
x = collect(1:10)
mean(x)
```




    5.5




```julia
var(x)
```




    9.166666666666666




```julia
std(x)
```




    3.0276503540974917




```julia
median(x)
```




    5.5




```julia
sum(x)
```




    55




```julia
minimum(x)
```




    1




```julia
maximum(x)
```




    10



欠損値（`missing`）を含む場合は，`skipmissing()` で欠損値を除いてからそれぞれの関数を適用する。


```julia
y = [2, 4, 6, 9, missing, 5]
mean(skipmissing(y))
```




    5.2




```julia
z = skipmissing(y)
mean(z)
```




    5.2



幾何平均 `geomean()`，調和平均 `harmmean()`，分位数 `quantile()` を使うためには `using StatsBase` が必要である。


```julia
using StatsBase
geomean(x)
```




    4.528728688116766




```julia
harmmean(x)
```




    3.414171521474055




```julia
quantile(x)
```




    5-element Vector{Float64}:
      1.0
      3.25
      5.5
      7.75
     10.0



### 二変数統計関数 `cor()`, `cov()`

相関係数を求める `cor()`，共分散を求める `cov()` がある。


```julia
x = [2, 1, 4, 3, 2, 5, 5]
y = [3, 4, 5, 2, 1, 6, 9]
cor(x, y)
```




    0.7367460807153253




```julia
cov(x, y)
```




    3.119047619047619



## ベクトルを逆順にする `reverse()`, `reverse!()`

`reverse(v)` は逆順に並べたコピーを返す。`reverse!(v)` はインプレースで逆順にするので，結果は `v` に保存される（元の `v` は破壊される）。


```julia
x = [1, 2, 3, 4, 5]
y = reverse(x)
println(x)
println(y)
```

    [1, 2, 3, 4, 5]
    [5, 4, 3, 2, 1]



```julia
x = [1, 2, 3, 4, 5]
reverse!(x)
println(x)
```

    [5, 4, 3, 2, 1]


## ベクトルを昇順にソートする `sort()`, `sort!()`

`sort(v)` はソートしたコピーを返す。`sort!(v)` はインプレースでソートするので，結果は `v` に保存される（元の `v` は破壊される）。


```julia
x = [3, 2, 1, 6, 5, 4]
y = sort(x)
println(x)
println(y)
```

    [3, 2, 1, 6, 5, 4]
    [1, 2, 3, 4, 5, 6]



```julia
x = [3, 2, 1, 6, 5, 4]
sort!(x)
println(x)
```

    [1, 2, 3, 4, 5, 6]


降順（逆順）にソートするときには，`rev=true` を指定する。


```julia
x = [3, 2, 1, 6, 5, 4]
sort!(x, rev=true)
println(x)
```

    [6, 5, 4, 3, 2, 1]


## 並べ替えベクトルを求める `sortperm()`

ベクトルの中で最も小さい要素は何番目の要素か，2 番目に小さい要素は何番目の要素か，...，もっとも大きい要素は何番目の要素かを表すベクトルを返す。


```julia
x = [3, 2, 1, 6, 5, 4]
order = sortperm(x)
```




    6-element Vector{Int64}:
     3
     2
     1
     6
     5
     4



最も小さい要素は 1 でそれは `x` の中の 3 番目の要素，<br>2 番目に小さい要素は 2 でそれは `x` の中の 2 番目の要素<br>最も大きい要素は 6 でそれは `x` の中の 4 番目の要素

`x[sortperm(x)]` により昇順ソートができる。


```julia
x[order]
```




    6-element Vector{Int64}:
     1
     2
     3
     4
     5
     6



`x` と `y` の二つのベクトルで，それぞれの要素が対応しているときに，要素の対応関係を保ったまま `x` を昇順に並べるときに応用できる。


```julia
y = [2, 1, 3, 5, 4, 7]
x1 = x[order]
y1 = y[order]
println(x1)
println(y1)
```

    [1, 2, 3, 4, 5, 6]
    [3, 1, 2, 7, 4, 5]