# メモ

Chainer のチュートリアルサイトが Open in Colab ボタンのあるサイトだったのでそこから拾い読み

https://tutorials.chainer.org/ja/tutorial.html

オンライン学習資料

- 数学の知識
- Python を用いたコーディングの基本
- 機械学習・ディープラーニングの基礎的な理論
- 画像認識や自然言語処理などに機械学習を応用する方法

が学べるとのこと。

チュートリアルサイトのおすすめの利用方法

1. `Open in Colab` ボタンで Colab で開く
2. メニューのドライブにコピー、で自分のドライブにコピーする
3. コードを実行しながら読んでいく

と言う手順が、本チュートリアルサイトのおすすめの利用方法

# Colab の便利なショートカット

| 説明                 | コマンド      |
| -------------------- | ------------- |
| Markdownモードへ変更 | Ctrl + M → M |
| Codeモードへ変更     | Ctrl + M → Y |
| セルの実行           | Shift + Enter |
| セルを上に追加       | Ctrl + M → A |
| セルを下に追加       | Ctrl + M → B |
| セルのコピー         | Ctrl + M → C |
| セルの貼り付け       | Ctrl + M → V |
| セルの消去           | Ctrl + M → D |
| コメントアウト       | Ctrl + /      |

```python
#@title
%%html
<style>
    /* table {
        border-collapse: collapse;
        border: 2px solid rgb(200, 200, 200);
        letter-spacing: 1px;
        margin: auto;
    } */

    td,
    th {
        border: 1px solid rgb(190, 190, 190);
        padding: 10px 20px;
    }

    tr:nth-child(even) td {
        /* background-color: rgb(250, 250, 250); */
        background-color: red;
    }

    tr:nth-child(odd) td {
        background-color: rgb(80,30,0);
        color: white;
    }

    /* tr td:nth-child(3) {
        color: red;
        font-size: 300%;
    } */
</style>

<table>
<thead>
<tr>
<th>説明</th>
<th>コマンド</th>
</tr>
</thead>
<tbody>
<tr>
<td>Markdownモードへ変更</td>
<td>Ctrl + M → M</td>
</tr>
<tr>
<td>Codeモードへ変更</td>
<td>Ctrl + M → Y</td>
</tr>
<tr>
<td>セルの実行</td>
<td>Shift + Enter</td>
</tr>
<tr>
<td>セルを上に追加</td>
<td>Ctrl + M → A</td>
</tr>
<tr>
<td>セルを下に追加</td>
<td>Ctrl + M → B</td>
</tr>
<tr>
<td>セルのコピー</td>
<td>Ctrl + M → C</td>
</tr>
<tr>
<td>セルの貼り付け</td>
<td>Ctrl + M → V</td>
</tr>
<tr>
<td>セルの消去</td>
<td>Ctrl + M → D</td>
</tr>
<tr>
<td>コメントアウト</td>
<td>Ctrl + /</td>
</tr>
</tbody>
</table>

```

説明
コマンド

Markdownモードへ変更
Ctrl + M → M

Codeモードへ変更
Ctrl + M → Y

セルの実行
Shift + Enter

セルを上に追加
Ctrl + M → A

セルを下に追加
Ctrl + M → B

セルのコピー
Ctrl + M → C

セルの貼り付け
Ctrl + M → V

セルの消去
Ctrl + M → D

コメントアウト
Ctrl + /

# Python 入門

とてもすっきりした Python 入門

- 変数、リスト、タプル、辞書
- 制御構文
- 関数、スコープ
- クラス、継承

```python
a = 1
```

```python
b = 1.2
```

```python
c = 'Chainer'
```

```python
type(a)
```

    int

```python
type(b)
```

    float

```python
type(c)
```

    str

Python では、`.` を含まない連続した数字を `int`、

直前・直後も含め `.` が含まれる連続した数字を `float`

だと自動的に解釈する。

例えば、`7` や `365` は `int` だが、

`2.718`、`.25`、`10.` などは `float` になる。

実数の `0` は `0.0` とも `.0` とも `0.` とも書くことができる。

```python
type(0)
```

    int

```python
type(0.)
```

    float

```python
type(.0)
```

    float

Python 3 では、 `/` 記号を用いて除算を行う場合、

除数（割る数）と被除数（割られる数）が整数であっても、

計算結果として実数が返る。

計算結果として実数を返す除算のことを特に、

**真の除算 (true division)** と言う。

一方、商（整数部分）を返すような除算演算子として、

 `//` 記号が用意されている。

 計算結果として商を返す除算のことを、 **切り捨て除算 (floor division)** と呼ぶ。

```python
# 整数と整数で切り捨て除算 -> 結果は整数
3 // 2
```

    1

```python
# 整数と整数で切り捨て除算 -> 結果は整数
4 // 2
```

    2

整数や実数と文字列の演算は基本的にエラーになる。

```python
# a + c #=> TypeError: unsupported operand type(s) for +: 'int' and 'str'
```

```python
# str と int で乗算
c = 'Chainer'
c * 3
```

    'ChainerChainerChainer'

上のコードは、`c` と言う文字列を `3` 回繰り返す、と言う意味になる。

`str` 同士は足し算を行うことができる。

```python
name1 = 'Chainer'
name2 = 'チュートリアル'

name1 + name2
```

    'Chainerチュートリアル'

整数と文字列を連結したいこともある。

例えば、`1` と言う整数に、 `'番目'` と言う文字列を足して `'1番目'` と言う文字列を作りたいような場合には、型を変換する**キャスト (cast)** と言う操作をする必要がある。

何かを `int` にキャストしたい場合は `int()` と言う組み込み関数を使い、

`str` にキャストしたい場合は `str()` と言う組み込み関数を使う。

```python
type(str(1))
```

    str

```python
str(1) + '番目'
```

    '1番目'

Python には、他にも幾つかの算術演算子が用意されている。

| 演算 | 記号 |
|------|------|
| 累乗 | `**` |
|  剰余　 | `%` |

```python
# 累乗
2 ** 3
```

    8

`%` を使って、`9` を `2` で割った余りを計算してみる。

```python
# 剰余
9 % 2
```

    1

比較演算子は、2 つの値の比較を行うための演算子である。

| 演算 | 記号 |
|------|------|
| 小なり | `<` |
| 大なり | `>` |
| 以下 | `<=` |
| 以上 | `>=` |
| 等しい | `==` |
| 等しくない | `!=` |

エスケープシーケンス

```python
print('Hello\nWorld')
```

    Hello
    World

```python
print('Hello\tWorld')
```

    Hello	World

**文字列メソッド**

`str` 型の変数には、いくつか便利な機能がついている。

例えば、その変数が持つ全ての文字を小文字や大文字に変換する `lower()` や `upper()` といった機能がある。

型が持っている関数を**メソッド (method)** と呼ぶ。

```python
name = 'Chainer'
name
```

    'Chainer'

```python
# すべてを小文字に変換
name.lower()
```

    'chainer'

```python
# すべてを大文字に変換
name.upper()
```

    'CHAINER'

文字列メソッドの一つに、 `format()` がある。

これは、ある文字列の一部分に、あとから別な文字列を埋め込むために使用する。

対象の文字列には `{}` で予め値を埋め込みたい場所を指定しておく。

```python
name = 'Chainer'

'{} チュートリアルへようこそ'.format(name)
```

    'Chainer チュートリアルへようこそ'

```python
name1 = 'Chainer'
name2 = 'チュートリアル'

'{} {}へようこそ'.format(name1, name2)
```

    'Chainer チュートリアルへようこそ'

`format()` メソッドを用いると `int` 型 や `float` 型の変数を、`str` 型へ明示的にキャストすることなく文字列に埋め込むことができる。

```python
version = 3.7

'Python {}'.format(version)
```

    'Python 3.7'

**浮動小数点数がもつメソッド**

`int` 型の変数や、`float` 型の変数にも、その型の特徴に合わせた機能が、メソッドとして提供されている。

例えば、`float` 型の変数には、`as_integer_ratio()` と言うメソッドがあり、比がその浮動小数点数の値となるような整数の組を返す。

例えば、0.5 と言う値は、分数で表すと $\frac{1}{2}$ である。
これは、以下のようにして調べることができる。

```python
0.5.as_integer_ratio()
```

    (1, 2)

0.25 であれば、$\frac{1}{4}$ となる。

```python
0.25.as_integer_ratio()
```

    (1, 4)

```python
type(0.25.as_integer_ratio())
```

    tuple

**複合データ型**

以下の 3つの複合データ型がある。

- リスト (list)
- タプル (tuple)
- 辞書 (dictionary)

**リスト**

複数の変数を `,` （カンマ）区切りで並べ、それらの全体を `[ ]` で囲んだものを **リスト (list)** と言う。
リストに含まれる値を**要素**と呼び、整数の**インデックス** （要素番号）を使ってアクセスする。

```python
# リスト型の変数を定義
numbers = [4, 5, 6, 7]

# 値の確認
print(numbers)
```

    [4, 5, 6, 7]

```python
# 型の確認
type(numbers)
```

    list

`numbers` には 4 つの数値が入っており、**要素数** は 4 である。
リストの要素数は、リストの**長さ (length)** とも呼ばれ、組み込み関数の `len()` を用いて取得することができる。

```python
# 要素数の確認
numbers = [4, 5, 6, 7]
print(len(numbers))
numbers.append(3)
print(len(numbers))
```

    4
    5

上のコードで len() と append() の使い方が違う。 len は組み込み関数で、append は list のメソッドだとよく説明されるが、言葉の使い方がなんとなく変じゃないか。 それでは len が関数で append が関数ではないように読めてしまう。 メソッドは型(クラス)が持っている関数で、関数と言う意味では同じである。

`dir(numbers)`

とするとリストの持っているメソッド(関数)がわかってその中に `__len__` と言うのがあるので、次のように使ってみると使える。

歴史的な判断かもしれない。

```python
numbers.__len__()
```

    5

`dir()` とすると出てくる一覧に `__builtin__` と言うのがあるので調べてみる。

```python
# dir(__builtin__) #=? 結構な数の組み込み関数があるのがわかる
```

```python
# 実験
print(abs(-5))
print((-5).__abs__())
```

    5
    5

リストの各要素へアクセスする方法はいくつかある。
最も簡単な方法は bracket `[]` を使ってアクセスしたい要素番号を指定して、リストから値を取り出したり、その位置の値を書き換えたりする方法である。

先頭の要素のインデックス番号は `0` である。

```python
# 先頭の要素にアクセス
numbers[0]
```

    4

```python
# 先頭から3番目の要素にアクセス
numbers[2]
```

    6

```python
# 2 番目の要素を書き換え
numbers[1] = 10
```

```python
# 値の確認
numbers
```

    [4, 10, 6, 7, 3]

また、インデックスに負の値を指定すると、末尾からの位置となる。
要素番号 `-1` で最後の要素を参照することができる。

```python
# 末尾の要素にアクセス
numbers[-1]
```

    3

```python
# 末尾から3番目の要素にアクセス
numbers[-3]
```

    6

次に、リストから一度に複数の要素を取り出す操作である**スライス (slice)** を紹介する。
`開始位置:終了位置` のようにコロン `:` を用いてインデックスを範囲指定し、複数の部分要素にアクセスする。
このスライスの処理は、この後の章でも多用するため、慣れておく。

例えば、先頭から 2 つの要素を取り出したい場合、以下のように指定する。

```python
numbers[0:2]
```

    [4, 10]

```python
numbers
```

    [4, 10, 6, 7, 3]

```python
slice(0,2)
```

    slice(0, 2, None)

```python
numbers[slice(0,2)]
```

    [4, 10]

`開始位置:終了位置` と指定することで、開始位置から**終了位置のひとつ手前**までの要素を抽出する。
終了位置に指定したインデックスの値は含まれないことに注意する。

また、指定する開始番号が `0` である場合、以下のような略記がよく用いられる。

```python
numbers[:2]
```

    [4, 10]

このように、先頭のインデックスは省略することができる。
このような記法を使う場合は、終了位置を示す数字を**取り出したい要素の個数**と捉えて、**先頭から 2 つを取り出す**操作だと考えると分かりやすくなる。

同様に、ある位置からリストの末尾までを取り出す場合も、終了位置のインデックスを省略することができる。
例えば、2 個目の要素から最後までを取り出すには以下のようにする。

```python
numbers[1:]
```

    [10, 6, 7, 3]

この場合は、取り出される要素の個数は `len(numbers) - 1` 個となることに注意する。

以上から、`numbers[:2]` と `numbers[2:]` は、ちょうど 2 個目の要素を境に `numbers` の要素を 2 分割した前半部分と後半部分になっている。
ここで、インデックスが 2 の要素自体は**後半部に含まれる**と言うことに注意する。

また、開始位置も終了位置も省略した場合は、すべての要素が選択される。

```python
numbers[:]
```

    [4, 10, 6, 7, 3]

現状では、`numbers[:]` と `numbers` の結果が同じであるため、どのように使用するか疑問に思われるかも知れない。
しかし、後の章では NumPy と言うライブラリを用いてリストの中にリストが入ったような**多次元配列 (multidimensional array)** を扱っていく。

そして多次元配列を用いて行列を表す場合には、`0 列目のすべての値`を抽出するために `[:, 0]` のような記法を用いるケースが登場する。
これは Python 標準の機能ではないが、Python 標準のスライス表記を拡張したものになっている。

```python
x = [[1,2],[3,4]]
x[:][0]
```

    [1, 2]

リストは数値以外に、文字列を扱うこともでき、また複数の型を同一のリスト内に混在させることもできる。

```python
# 文字列を格納したリスト
array = ['hello', 'world']
array
```

    ['hello', 'world']

```python
len('hello')
```

    5

```python
# 複数の型が混在したリスト
array = [1, 1.2, 'Chainer']
array
```

    [1, 1.2, 'Chainer']

リストにリストを代入することもできる。
また、Python 標準のリストでは入れ子になったリスト内の要素数がばらばらでも問題ない。

```python
array = [[1, 1.2, 'Chainer', True], [3.2, 'Tutorial']]
array
```

    [[1, 1.2, 'Chainer', True], [3.2, 'Tutorial']]

リストを使う際に頻出する操作として、**リストへの値の追加**がある。
リスト型には `append()` と言うメソッドが定義されており、これを用いてリストの末尾に新しい値を追加することができる。

上記の `array` に値を追加してみる。

```python
# 末尾に 2.5 を追加
array.append(2.5)
```

```python
# 値の確認
array
```

    [[1, 1.2, 'Chainer', True], [3.2, 'Tutorial'], 2.5]

また、今後頻出する処理として、**空のリスト**を定義しておき、そこに後段の処理の中で適宜新たな要素を追加していくと言う使い方がある。

```python
# 空のリストを定義
array = []

# 空のリストに要素を追加
array.append('Chainer')
array.append('チュートリアル')

array
```

    ['Chainer', 'チュートリアル']

**タプル**

**タプル (tuple)** はリストと同様に複数の要素をまとめた型だが、リストとは異なる点として、定義した後に**中の要素を変更できない**と言う性質を持つ。

タプルの定義には丸括弧 parenthesis `( )`を用いる。

```python
# タプルを定義
array = (4, 5, 6, 7)
array
```

    (4, 5, 6, 7)

```python
# 型の確認
type(array)
```

    tuple

タプルの定義する際に `( )` を使用したため、要素へのアクセスも `( )` を使うように感じるかもしれないが、実際にはリストと同様 `[ ]` を使用する。

```python
# 先頭の要素へアクセス
array[0]
```

    4

```python
# リストと同様、スライスも使用可能
array[:3]
```

    (4, 5, 6)

先述の通り、タプルは各要素の値を変更することができない。
この性質は、定数項などプログラムの途中で書き換わってしまうことが望ましくないものをまとめて扱うのに便利である。

実際に、タプルの要素に値の書き換えを行うとエラーが発生する。

```python
# array[0] = 10 #=> TypeError: 'tuple' object does not support item assignment
```

`tuple` のように中身が変更できない性質のことを**イミュータブル (immutable)**であると言う。反対に、`list` のように中身が変更できる性質のことを**ミュータブル (mutable)**であると言う

タプルも Chainer でデータセットを扱うときなどに頻出する型である。その性質と取り扱い方を覚えておく。

**辞書**

リストやタプルでは、複数の値をまとめて扱うことができた。

定期テストの結果をまとめることを考えてみる。

例えば、数学 90 点、理科 75 点、英語 80 点だったと言う結果を `scores = [90, 75, 80]` とリストで表してみる。
しかし、これでは**何番目がどの教科の点数に対応するか**、一見して分かりにくい。

Python の `dict` 型は、**キー (key)** とそれに対応する**値 (value)** をセットにして格納することができる型であり、このようなときに便利である。

リストやタプルでは、各要素にアクセスする際に整数のインデックスを用いていたが、辞書ではキーでインデックス化されているため、整数や文字列など、色々なものを使って要素を指定することができる。

辞書は brace `{}` を用いて定義し、要素にアクセスする際には、リストやタプルと同様に `[ ]` を使用し、`[ ]` の中にキーを指定して対応する値を取り出す。

```python
# 辞書を定義
scores = {'Math': 90, 'Science': 75, 'English': 80 }
scores
```

    {'English': 80, 'Math': 90, 'Science': 75}

```python
# key が Math の value にアクセス
scores['Math']
```

    90

```python
# key に日本語を使用することも可能
scores = {'数学': 90, '理科': 75, '英語': 80}
scores
```

    {'数学': 90, '理科': 75, '英語': 80}

```python
scores['数学']
```

    90

他の人が定義した辞書に、**どのようなキーが存在するのか**を調べたいときがある。
辞書には、そのような場合に使える便利なメソッドがいくつか存在する。

- `keys()`: キーのリストを取得。`dict_keys` と言うリストと性質が似た型が返る
- `values()`: 値のリストを取得。`dict_values` と言うリストと性質が似た型が返る
- `items()`: 各要素の `(key, value)` のタプルが並んだリストを取得。`dict_items` と言うリストと性質が似た型が返る

```python
# キーのリスト
scores.keys()
```

    dict_keys(['数学', '理科', '英語'])

```python
# 値のリスト
scores.values()
```

    dict_values([90, 75, 80])

```python
# (キー, 値)と言うタプルを要素とするリスト
scores.items()
```

    dict_items([('数学', 90), ('理科', 75), ('英語', 80)])

`dict_keys`, `dict_values`, `dict_items` と新しい型が登場したが、これは辞書型特有の型であり厳密には標準のリストとは異なるが、リストと性質の似た型であると言う程度の認識で問題ない。

辞書に要素を追加する場合は、新しいキーを指定して値を代入する。

```python
scores['国語'] = 85
```

```python
scores
```

    {'国語': 85, '数学': 90, '理科': 75, '英語': 80}

また、既に存在するキーを指定した場合には、値が上書きされる。

```python
scores['数学'] = 95
```

```python
scores
```

    {'国語': 85, '数学': 95, '理科': 75, '英語': 80}

**制御構文 control structure, control flow**

複雑なプログラムを記述しようとすると、繰り返しの処理や、条件によって動作を変える処理が必要となる。
これらは**制御構文**を用いて記述する。

ここでは最も基本的な制御構文を 2 つ紹介する。

- 繰り返し (`for`, `while`)
- 条件分岐 (`if`)

Python の制御構文は、**ヘッダ (header)** と **ブロック (block)** と呼ばれる 2 つの部分で構成されている。
これらを合わせて **複合文 (compound statement)** と呼ぶ。

```
if 条件: # コロンが必要。 ヘッダー
    処理ブロック # インデントが必要。半角スペース4つ
```

上図に示すように、制御構文ではヘッダ行に `for` 文や `if-else` 句を記述し、行末に `:` 記号を書く。次に、ヘッダ行の条件で実行したい一連の処理文を、ブロックとしてその次の行以降に記述していく。その際、 **インデント (indent)** と呼ばれる空白文字を先頭に挿入することで、ブロックを表現する。同じ数の空白でインデントされた文がブロックとみなされる。

Python では、インデントとして**スペース 4 つ**を用いることが推奨されている。

**繰り返し（for 文）**

同じ内容のメールを宛名だけ個別に変えて、1000 人に一斉送信したい場合など、繰り返す処理を記述する制御構文である `for` を使う。

```
for 変数名 in イテラブルオブジェクト: ヘッダー
    ブロック処理
```

**イテラブルオブジェクト (iterable object)** とは、反復可能オブジェクトのことであり、要素を一度に 1 つずつ返せるオブジェクトのことを指す。
`range()` と言う組み込み関数を使うと、引数に与えた整数の回数だけ順番に整数を返すイテラブルオブジェクトを作ることができる。
`range(5)` と書くと、0, 1, 2, 3, 4 と言う整数 5 つを順番に返すイテラブルオブジェクトになる。

このイテラブルオブジェクトとして、リストやタプルも指定することができる。

```python
# 5回繰り返す
for i in range(5):
    print(i)
```

    0
    1
    2
    3
    4

上記の例では、イテラブルオブジェクトが1 つずつ返す値を変数 `i` で受け取っている。

最初は `i = 0` から始まっている。

最後の値も、`5` ではなく `4` となっている。

このように、`range()` に 1 つの整数を与えた場合は、その整数 - 1 まで 0 から 1 つずつ増えていく整数を順番に返す。

```python
# 繰り返し処理が終わった後の値の確認 => 今回の場合 4
i
```

    4

Jupyter Notebook では変数名をコードセルの最後の行に書いて実行するとその変数に代入されている値を確認できたが、for 文の中のブロックでは明示的に `print()` を使う必要がある。
`print()` を用いないと、以下のように何も表示されない。

```python
# 変数の値は表示されない
for i in range(5):
    i
```

for 文を使って、0 から始まって 1 ずつ大きくなっていく整数順番に取得し、これをリストのインデックスに利用すれば、リストの各要素に順番にアクセスすることができる。

```python
names = ['佐藤', '鈴木', '高橋']

for i in range(3):
    print(names[i])
```

    佐藤
    鈴木
    高橋

少し応用して、自動的に敬称をつけて表示してみる。

```python
for i in range(3):
    print('{}さん'.format(names[i]))
```

    佐藤さん
    鈴木さん
    高橋さん

上記のコードに関して、汎用性が低い点として、`range(3)` のように `3` と言う値を直接記述していることが挙げられる。

この `3` はリストの要素の数を意味しているが、リストの要素の数が変わると、このプログラムも書き換える必要があり、手間がかかったり、ミスが発生する原因となったりする。

リスト内の要素の数は、組み込み関数である `len()` を用いて取得できるため、これを使用した汎用性の高いプログラムに書き換える。

```python
len(names)
```

    3

```python
for i in range(len(names)):
    print('{}さん'.format(names[i]))
```

    佐藤さん
    鈴木さん
    高橋さん

これでリストの要素数に依存しないプログラムにすることができた。

また、リスト自体をイテラブルオブジェクトとして指定することにより、リスト要素数の取得も `[]` でのインデックス番号の指定もせずに、より可読性の高いプログラムを書くことができる。

```python
# リストをイテラブルオブジェクトに指定
for name in names:
    print('{}さん'.format(name))
```

    佐藤さん
    鈴木さん
    高橋さん

リストをイテラブルオブジェクトとして指定した場合、要素番号を取得できないが、状況によっては要素番号を使用したいことがある。

そのような場合は、`enumerate()` と言う組み込み関数を使う。
これにイテラブルオブジェクトを渡すと、`(要素番号, 要素)` と言うタプルを 1 つずつ返すイテラブルオブジェクトになる。

```python
# enumerate の使い方
for i, name in enumerate(names):
    message = '{}番目: {}さん'.format(i, name)
    print(message)
```

```python
# 実験
print(list(enumerate(names)))
```

    [(0, '佐藤'), (1, '鈴木'), (2, '高橋')]

`enumerate()` と同様、`for` 文と合わせてよく使う組み込み関数に `zip()` がある。

`zip()` は、複数のイテラブルオブジェクトを受け取り、その要素のペアを順番に返すイテラブルオブジェクトを作る。
このイテラブルオブジェクトは、渡されたイテラブルオブジェクトそれぞれの先頭の要素から順番に、タプルに束ねて返す。
このイテラブルオブジェクトの長さは、渡されたイテラブルオブジェクトのうち最も短い長さと一致する。

```python
# zip の使い方
names = ['Python', 'Chainer']
versions = ['3.7', '5.3.0']
suffixes = ['!!', '!!', '?']

for name, version, suffix in zip(names, versions, suffixes):
    print('{} {} {}'.format(name, version, suffix))

#実験
print(list(zip(names, versions, suffixes)))
```

    Python 3.7 !!
    Chainer 5.3.0 !!
    [('Python', '3.7', '!!'), ('Chainer', '5.3.0', '!!')]

`suffixes` の要素数は 3 だが、より短いイテラブルオブジェクトと共に `zip` に渡されたため、先頭から 2 つ目までしか値が取り出されていない。

**条件分岐（if 文）**

`if` は、指定した条件が `True` か `False` かによって、処理を変えるための制御構文である。
```
if 条件: # 条件が True であればブロック処理を実行。ヘッダー
    処理ブロック
elif 条件: # if の条件が False で追加の条件分岐(任意)。ヘッダー
    処理ブロック
else: # すべてが False の場合の条件分岐(任意)。ヘッダー
    処理ブロック
```

**python の if は文であって、式ではない。**

`elif` と `else` は任意であり、`elif` は 1 つだけでなく複数連ねることができる。

例えば、0 より大きいことを条件とした処理を書いてみる。

```python
# if の条件を満たす場合
a = 1

if a > 0:
    print('0より大きい')
else:
    print('0以下')
```

    0より大きい

```python
# if の条件を満たさない場合
a = -1

if a > 0:
    print('0より大きい')
else:
    print('0以下')
```

    0以下

また、`if` に対する条件以外の条件分岐を追加する場合は、下記のように `elif` を使う。

```python
a = 0

if a > 0:
    print('0より大きい')
elif a == 0:
    print('０')
else:
    print('0より小さい')
```

    ０

**繰り返し（while 文）**

繰り返し処理は、`for` 以外にも `while` を用いて記述することもできる。
`while` 文では、以下のように**ループを継続する条件**を指定する。
指定された条件文が `True` である限り、ブロックの部分に記述された処理が繰り返し実行される。

```
while 条件: # True であればブロック処理を実行。ヘッダー
    ブロック処理
```

`while` 文を使用した 3 回繰り返すプログラムは下記のとおりである。

```python
count = 0

while count < 3:
    print(count)
    count += 1
```

    0
    1
    2

ここで使われている `count` と言う変数は、ループの中身が何回実行されたかを数えるために使われている。
まず `0` で初期化し、ループ内の処理が一度行われるたびに `count` の値に 1 を足している。
この `count` を使った条件式を `while` 文に与えることで、ループを回したい回数を指定している。

一方、`while True` と指定すると、`True` は変数ではなく値なので、変更されることはなく、ループは無限に回り続ける。
`while` 文自体は無限ループの状態にしておき、ループの中で `if` 文を使って、ある条件が満たされた場合はループを中断する、と言う使い方ができる。
これには `break` 文が用いられる。

以下は、`break` 文を使って上のコードと同様に 3 回ループを回すコードである。

```python
count = 0

while True:
    print(count)
    count += 1

    if count == 3:
        break
```

    0
    1
    2

`count` の値が 3 と等しいかどうかが毎回チェックされ、等しくなっていれば `break` 文が実行されて `while` ループが終了する。

`while` 文を使って、指定された条件を満たして**いない**間ループを繰り返すと言う処理も書くことができる。`while` 文自体の使い方は同じだが、条件を反転して与えることで、与えた条件が `False` である間繰り返されるようにすることができる。

これには、ブール値を反転する `not` を用いる。
`not True` は `False` を返し、`not False` は `True` を返す。

```python
not True
```

    False

```python
not False
```

    True

```python
not 1 == 2
```

    True

このように、`not` はあとに続くブール値を反転する。
これを用いて、`count` が 3 **ではない**限りループを繰り返すと言うコードを `while` 文を使って書いてみる。

```python
count = 0

while not count == 3:
    print(count)
    count += 1
```

    0
    1
    2

**関数**

何かひとまとまりの処理を書いた際には、その処理のためのコードをまとめて、プログラム全体の色々な箇所から再利用できるようにしておくと、便利な場合がある。
ここでは、処理をひとまとめにする方法の一つとして**関数 (function)** を定義する方法を紹介する。

**関数を定義する**

```
def 関数名 (引数1,2,...): ヘッダー
    処理ブロック
```

例えば、**受け取った値を 2 倍して表示する関数**を作ってみる。

関数を定義するには、まず名前を決める必要がある。
今回は `double()` と言う名前の関数を定義してみる。

関数も制御構文と同じく**ヘッダー**と**ブロック**を持っている。

```python
# 関数 double() の定義
def double(x):
    print(2 * x)
```

```python
# 実験 1 行に書けるか => 書ける
def double(x): print (2*x)

double (3)
```

    6

```python
# 実験 無名関数 lambda => 定義と同じ構文
(lambda x: print (2*x))(3)
```

    6

```python
# 実験 無名関数 lambda => 定義と同じ構文
(lambda x:
     print (2*x))
(3)
```

    3

**関数は定義されただけでは実行されない。**
定義した関数を使用するためには、定義を行うコードとは別に、実行を行うコードが必要である。

```python
# 関数 double() の定義
def double(x):
    print(2 * x)
# 関数の実行
double(3)
```

    6

```python
double(5)
```

    10

```python
double(1.5)
```

    3.0

`double(x)` における `x` のように、関数に渡される変数や値のことを**引数 (argument, ひきすう)** と言う。
上の例は、名前が `double` で、1つの引数 `x` をとり、`2 * x` と言う計算を行い、その結果を表示している。

**複数の引数をとる関数**

複数の引数をとる関数を定義する場合は、関数名に続く `()` の中に、カンマ `,` 区切りで引数名を並べる。

例えば、引数を 2 つとり、足し算を行う関数 `add()` を作ってみる。

```python
# 関数の定義
def add(a, b):
    print(a + b)
```

```python
# 関数の実行
add(1, 2)
```

    3

```python
add(3, 2.5)
```

    5.5

```python
add(1, -5)
```

    -4

今回の `double()` や `add()` は定義を行い自作した関数だが、Python には予め多くの関数が定義されている。
そのような関数を**組み込み関数 (built-in function)** と呼ぶ。
すでに使用している `print()` や `len()`, `range()` などが、これに該当する。
組み込み関数の一覧は[こちら](https://docs.python.org/ja/3/library/functions.html)で確認することができる。

colab 環境で `dir(__builtin__)` でも確認できる

**引数をとらない関数**

引数をとらない関数を定義する場合でも、関数名の後に `()` を加える必要がある。

例えば、実行するとメッセージを表示する関数を定義して、実行してみる。

```python
# 引数のない関数の定義
def hello():
    print('Chainerチュートリアルにようこそ')
```

```python
# 引数のない関数の実行
hello()
```

    Chainerチュートリアルにようこそ

**引数のデフォルト値**

引数には、あらかじめ値を与えておくことができる。

これは、引数をとる関数を定義する際に、何も引数に値が渡されなかったときにどのような値がその引数に渡されたことにするかをあらかじめ決めておける機能で、その値のことを**デフォルト値**と呼ぶ。

例えば、上の `hello()` と言う関数に、`message` と言う引数をもたせ、そこにデフォルト値を設定しておく。

```python
def hello(message='Chainerチュートリアルにようこそ'):
    print(message)
```

この関数は引数に何も与えずに呼び出すと、「Chainerチュートリアルにようこそ」と言うメッセージを表示し、引数に別な値が渡されると、その値を表示する。

```python
hello()
```

    Chainerチュートリアルにようこそ

```python
hello('Welcome to Chainer tutorial')
```

    Welcome to Chainer tutorial

デフォルト値が与えられていない引数は、関数呼び出しの際に必ず何らかの値が渡される必要があるが、デフォルト値を持つ場合は、何も指定しなくても関数を呼び出すことができるようになる。

**返り値のある関数**

上で定義した足し算を行う関数 `add()` では、計算結果を表示するだけで、計算結果を呼び出し元に戻していない。
そのため、このままでは計算結果を関数の外から利用することができない。

そこで、`add()` 関数の末尾に `return` 文を追加して、計算結果を呼び出し元に返すように変更してみる。

```python
# 返り値のある関数の定義
def add(a, b):
    return a + b
```

このように、呼び出し元に返したい値を `return` に続いて書くと、その値が `add()` 関数を呼び出したところへ戻される。
`return` で返される値のことを**返り値 (return value)** と言う。

以下に、計算結果を `result` と言う変数に格納し、表示する例を示す。

```python
result = add(1, 3)

result
```

    4

計算結果が `result` に格納されているので、この結果を用いてさらに別の処理を行うことができる。

```python
result = add(1, 3)

result_doubled = result * 2

result_doubled
```

    8

また、返り値は「呼び出し元」に返されると書いた。
この「呼び出し元」と言うのは、関数を呼び出す部分のことで、上のコードは `add(1, 3)` の部分が `4` と言う結果の値になり、それが左辺の `result` に代入されている。

これを用いると、例えば「2 と 3 を足した結果と、1 と 3 を足した結果を、掛け合わせる」と言う計算が、以下のように書ける。

```python
add(2, 3) * add(1, 3)
```

    20

**変数のスコープ**

関数の中で定義した変数は基本的には関数の外では利用できない。
例えば、以下の例を見てみる。

```python
a = 1

# 関数の内部で a に 2 を代入
def change():
    a = 2

change()

a
```

    1

関数の外で `a = 1` と初期化した変数と同じ名前の変数に対して、`change()` 関数の内部で `a = 2` と言う代入を行っているにもかかわらず、`change()` 関数の実行後にも関数の外側では `a` の値は 1 のままになっている。
**関数の外側で定義された変数** `a` **に、関数内部での処理が影響していないことがわかる。**

なぜこうなるかと言うと、関数の中で変数に値が代入されるとき、その変数はその関数の**スコープ (scope)** でだけ有効な**ローカル変数**になり、関数の外にある同じ名前の変数とは別のものを指すようになるためである。
スコープとは、その変数が参照可能な範囲のことである。
上の例では、`a = 2` の代入を行った時点で`change()` 関数のスコープに `a` と言う変数が作られ、`change()` 関数の中からは `a` といえばこれを指すようになる。関数から抜けると、`a` は 1 を値に持つ外側の変数を指すようになる。

ただし、代入を行わずに、参照するだけであれば、関数の内側から外側で定義された変数を利用することができる。

```python
a = 1

def change():
    print('From inside:', a)

change()

print('From outside:', a)
```

    From inside: 1
    From outside: 1

この場合は、`change()` 関数のスコープには `a` と言う変数は作られないので、関数の中で `a` といえば外側で定義された変数を指す。

関数の外で定義された変数は**グローバル変数**と呼ばれる。
グローバル変数は、特に特別な記述を要せず参照することはできるが、関数の中で**代入**を行う場合は、`global` 文を使って、代入先をグローバル変数とする宣言を行う必要がある。

```python
a = 1

def change():
    global a  # a をグローバル変数である宣言
    a = 2       # グローバル変数への代入

# 関数の実行
change()

# 結果の確認 <- a の値が上書きされている
a
```

    2

`global a` と言う行を `change()` 関数内で `a` と言う変数を使用する前に追加すると、その行以降は `a` と言う変数への代入も関数の外側で定義されたグローバル変数の `a` に対して行われる。

**クラス**

**オブジェクト指向プログラミング (object-oriented programming)** の特徴の一つである**クラス (class)** は、**オブジェクト (object)** を生成するための設計図にあたるものである。

クラスから作成された実体のことを**インスタンス (instance)** または**オブジェクト (object)** とも呼び、**クラスから実体を作成する**と言う操作のことを**インスタンス化 (instantiation)** と呼ぶ。

**クラスの定義**

それでは、家の設計図を表す `House` と言うクラスを定義してみる。

`House` クラスには、インスタンス化されたあとに、各インスタンス、すなわち誰か特定の人の家ごとに異なる値を持つ、`name_plate` と言う変数を持たせてみる。

`name_plate` と言う変数には、個別の家の表札に表示するための文字列が与えられるが、クラスを定義する際には「`name_plate` と言う変数を持つことができる」ようにしておくだけでよく、**実際にその変数に何か具体的な値を与える必要はない。**

クラスは、**設計図**であればよく、具体的な値を持たせなくてもよいためである。

具体的な値は、個別の家を作成するとき、すなわちインスタンス化の際に与え、各インスタンスが `name_plate` と言う値に自分の家の表札の名前を保持するようにする。

このような、インスタンスに属している変数を**属性 (attribute)** と呼ぶ。同様に、インスタンスから呼び出すことができる関数のことを**メソッド (method)** と呼ぶ。

クラスは、以下のような構文を使って定義する。

具体的には、以下のようになる。
```
class クラス名: ヘッダー
    def メソッド名(引数1, ...): ヘッダー
        ブロック処理
```

```python
# クラスの定義
class House:
    # __init__() メソッドの定義
    def __init__(self, name):
        self.name_plate = name
```

ここで、`__init__()` と言う名前のメソッドが `House` クラスの中に定義されている。
メソッドの名前は自由に名付けることができるが、いくつか特別な意味を持つメソッド名が予め決められている。
`__init__()` はそういったメソッドの一つで、**インスタンス化する際に自動的に呼ばれるメソッド**である。

`House` クラスの `__init__()` は、`name` と言う引数をとり、これを `self.name_plate` と言う変数に代入している。
この `self` と言うのは、クラスがインスタンス化されたあと、作成されたインスタンス自身を参照するのに用いられる。
これを使って、`self.name_plate = name` とすることで、作成された個別のインスタンスに属する変数 `self.name_plate` へ、引数に渡された `name` が持つ値を代入することができる。
`self` が指すものは、各インスタンスから見た「自分自身」なので、各インスタンスごとに異なる。
これによって、`self.name_plate` は各インスタンスに紐付いた別々の値を持つものとなる。

メソッドは、インスタンスから呼び出されるとき自動的に第一引数にそのインスタンスへの参照を渡す。
そのため、メソッドの第一引数は `self` とし、渡されてくる自分自身への参照を受け取るようにしている。
ただし、呼び出す際には**そのインスタンスを引数に指定する必要はない。**
以下に具体例を示し、再度このことを確認する。

それでは、上で定義した `House` クラスのインスタンスを作成してみる。
クラスのインスタンス化には、クラス名のあとに `()` を追加して、クラスを呼び出すような記法を使う。
この際、関数を呼び出すときと同様にして、`()` に引数を渡すことができる。
その引数は、`__init__()` メソッドに渡される。

```python
my_house = House('Chainer')
```

`House` と言うクラスの `__init__()` メソッドに、`'Chainer'` と言う文字列を渡している。
`my_house` が、`House` クラスから作成されたインスタンスである。
ここで、クラス定義では `__init__()` メソッドは `self` と `name` と言う 2 つの引数をとっていたが、呼び出しの際には `'Chainer'` と言う一つの引数しか与えていない。
この `'Chainer'` と言う文字列は、1 つ目の引数であるにも関わらず、`__init__()` メソッドの定義では 2 つ目の引数であった `name` に渡される。
前述のように、**メソッドは、インスタンスから呼び出されるとき自動的に第一引数にそのインスタンスへの参照を渡す**ためである。
この自動的に渡される自身への参照は、呼び出しの際には明示的に指定しない。
また、かならず 1 つ目の引数に自動的に渡されるため、呼び出し時に明示的に与えられた引数は 2 つ目以降の引数に渡されたものとして取り扱われる。

それでは次に、このクラスに `hello()` と言うメソッドを追加し、呼び出すと誰の家であるかを表示すると言う機能を実装してみる。

```python
# クラスの定義
class House:

    # __init__() の定義
    def __init__(self, name):
        self.name_plate = name

    # メソッドの定義
    def hello(self):
        print('{}の家である。'.format(self.name_plate))
```

それでは、2 つのインスタンスを作成して、それぞれから `hello()` メソッドを呼び出してみる。

```python
sato = House('佐藤')
suzuki = House('スズキ')

sato.hello()   # 実行の際には hello() の引数にある self は無視
suzuki.hello() # 実行の際には hello() の引数にある self は無視
```

    佐藤の家である。
    スズキの家である。

`sato` と言うインスタンスの `name_plate` 属性には、`'佐藤'` と言う文字列が格納されている。
`suzuki` と言うインスタンスの `name_plate` 属性には、`'スズキ'` と言う文字列が格納されている。
それぞれのインスタンスから呼び出された `hello()` メソッドは、`self.name_plate` に格納された別々の値を `print()` を用いて表示している。

このように、同じ機能を持つが、インスタンスによって保持するデータが異なったり、一部の動作が異なったりするようなケースを扱うのにクラスを利用する。
Python の `int` 型、`float` 型、`str` 型…などは、実際には `int` クラス、`float` クラス、`str` クラスであり、それらの中では個別の変数（インスタンス）がどのような値になるかには関係なく、同じ型であれば共通して持っている機能が定義されている。
`5` や `0.3` や `'Chainer'` などは、それぞれ `int` クラスのインスタンス、`float` クラスのインスタンス、`str` クラスのインスタンスである。

以上から、クラスを定義すると言うのは、**新しい型を作る**と言うことでもあると分かる。

**継承**

あるクラスを定義したら、その一部の機能を変更したり、新しい機能を付け足したりしたくなることがある。
これを実現する機能が**継承 (inheritance)** である。
例えば、`Link` と言うクラスを定義し、そのクラスを継承した `Chain` と言う新しいクラスを作ってみる。
まず、`Link` クラスを定義する。

```python
class Link:

    def __init__(self):
        self.a = 1
        self.b = 2
```

この `Link` と言うクラスは、インスタンス化を行う際には 1 つも引数をとらないが、属性として `a` と `b` の 2 つの変数を保持し、それぞれには `__init__()` メソッドで 1 と 2 と言う値が代入される。
このクラスのインスタンスを作成してみる。

```python
l = Link()

l.a
```

    1

```python
l.b
```

    2

`l` と言う `Link` クラスのインスタンスが持つ 2 つの属性を表示している。
インスタンス化を行った際に `__init__()` メソッドの中で代入していた値が、表示されている。

次に、このクラスを**継承**する、`Chain` と言うクラスを定義してみる。
継承を行う場合は、クラス定義の際にクラス名に続けて `()` を書き、その中にベースにしたいクラスの名前を書く。
`()` の中に書かれたクラスのことを、定義されるクラスの**親クラス**と言う。
それに対し、`()` の中に書かれたクラスからみると、定義されるクラスは**子クラス**と呼ばれる。
親から子へ機能が受け継がれるためである。

```python
class Chain(Link):

    def sum(self):
        return self.a + self.b
```

`Chain` クラスは `__init__()` メソッドの定義を持ちない。
`__init__()` メソッドが定義されていない場合、親クラスの `__init__()`  メソッドが自動的に呼び出される。
そのため、`Chain` クラスでは一見何も属性を定義していないように見えるが、インスタンス化を行うと親クラスである `Link` の `__init__()`  メソッドが自動的に実行され、`a`、`b` と言う属性が定義される。
以下のコードで確認してみる。

```python
# Chain クラスをインスタンス化
c = Chain()

c.a
```

    1

```python
c.b
```

    2

`Chain` クラスの `sum()` メソッドでは、この親クラスの `__init__()`  メソッドで定義されている 2 つの属性を足し合わせて返している。
今作成したインスタンスから、この `sum()` メソッドを呼び出してみる。

```python
# sum メソッドを実行
c.sum()
```

    3

このように、**親クラスを継承し、親クラスに無かった新しい機能が追加された、新しいクラスを定義することができる。**

それでは、この `Chain` と言うクラスにも `__init__()`  メソッドを定義して、新しい属性 `c` を定義し、`sum()` メソッドでは親クラスの `a`、`b` と言う属性とこの新たな `c` と言う属性の 3 つの和を返すように変更してみる。

```python
class Chain(Link):

    def __init__(self):
        self.c = 5  # self.c を新たに追加

    def sum(self):
        return self.a + self.b + self.c

# インスタンス化
C = Chain()
```

```python
# error
# C.sum()
```

エラーが出た。

**エラーメッセージを読む。**

> AttributeError: 'Chain' object has no attribute 'a'

`'Chain'` と言うオブジェクトは、`'a'` と言う名前の属性を持っていない、と言われている。
`a` と言う属性は、`Chain` の親クラスである `Link` の `__init__()`  メソッドで定義されている。
そのため、`Chain` クラスをインスタンス化する際に、親クラスである `Link` の `__init__()`  メソッドが呼ばれているのであれば、このエラーは起こらないはずである。
なぜエラーとなってしまったのだろうか。

それは、`Chain` クラスにも `__init__()` メソッドを定義したため、親クラスである `Link` の `__init__()`  メソッドが上書きされてしまい、実行されなかったためである。
しかし、親クラスの `__init__()`  メソッドを明示的に呼ぶことで、これは解決できる。

それには、`super()` と言う組み込み関数を用いる。
これを用いると、子クラスから親クラスを参照することができる。

```python
class Chain(Link):

    def __init__(self):
        # 親クラスの `__init__()` メソッドを呼び出す
        super().__init__()

        # self.c を新たに追加
        self.c = 5

    def sum(self):
        return self.a + self.b + self.c

# インスタンス化
c = Chain()
```

```python
c.sum()
```

    8

今回はエラーが起きない。
`Link` クラスの `__init__()`  メソッドの冒頭で、まず親クラスの `__init__()`  メソッドを実行し、`a`、`b` と言う属性を定義しているためである。

あるクラスを継承して作られたクラスを、さらに継承して別のクラスを定義することもできる。

```python
class MyNetwork(Chain):

    def mul(self):
        return self.a * self.b * self.c
```

`MyNetwork` クラスは、`Link` クラスを継承した `Chain` クラスをさらに継承したクラスで、`a`、`b`、`c` と言う 3 つの属性を掛け合わせた結果を返す `mul()` と言うメソッドを持つ。

このクラスのインスタンスを作成し、`mul()` を実行してみる。

```python
net = MyNetwork()

net.mul()
```

    10

$1 \times 2 \times 5 = 10$ が返ってきた。

以上で、Python の基本についての解説を終了する。

Python には他にもここでは紹介されていない多くの特徴や機能がある。

Pythonチュートリアル

https://docs.python.org/ja/3/tutorial/index.html

# 機械学習に使われる数学

次章よりディープラーニングを含む機械学習に必要な数学の

- 微分
- 線形代数
- 確率統計

について、紹介していく。

その前に、本章では**機械学習 (machine learning)** の考え方について大枠を掴み、どの部分でそれぞれの項目が登場するかを把握しておく。

**機械学習とは**

機械学習は、与えられたデータから、未知のデータに対しても当てはまる規則やパターンを抽出したり、それらを元に未知のデータを分類したり、予測したりする手法を研究する学術領域である。

機械学習は様々な技術に応用されており、例えば画像認識、音声認識、文書分類、医療診断、迷惑メール検知、商品推薦など、幅広い分野で重要な役割を果たしている。

**教師あり学習の考え方**

機械学習の代表的な問題設定として、**教師あり学習 (supervised learning)** と言うものがある。
これは、問題に対して予め答えを用意しておき、予想された答えと実際の答えの違いが小さくなるように訓練を行う方法である。

もう少し具体的に教師あり学習の考え方を説明してみる。
例えば、以下の図のような赤い点の集まりがあったとする。

**図表**

この図は、横軸が $x$ 軸、縦軸が $t$ 軸となっている。
この赤い点の 1 つ 1 つは、$x$ と $t$ の値の組を表している。
図から、$x = 0$ 付近では $t$ も $0$ 付近の値をとることが多いようだ。
また、$x = 200$ 付近では、$t$ は $40$ 前後の値をとっているように見える。
それでは、$x = -200$ のとき、$t$ はどのような値をとるだろうか。

このように、与えられたデータから関係性を予想し、未知のデータに対しても筋のよい見通しを立てることが、教師あり学習の代表的な目標の 1 つである。

メモ $\quad$ この図はビットマップの png だがこのような図を matplotlib か svg でコードで書いておきたい。 外は信用ができない。 いつまであるか、ということと、紐付け方法が変わる可能性がある。

アイデアとしては、y=ax + b の数式の各点からランダムに遠い点を適当な数プロットすればよい。 やってみよう。

**直線による近似**

次に、以下のような直線の方程式を考えてみる。

$$
f(x) = wx + b
\tag{2.1}
\label{line}
$$

**図表**

これは、1 つの入力 $x$ を与えると 1 つの出力を返す関数 $f$ を表していて、この関数は傾き $w$ と切片 $b$ の **2 つのパラメータで特徴づけられている。**
上の図は、$w = 0.5$、$b = 50$ の場合を表している。
ここで、初めの図にあった赤い点の集まりに見られる $x$ と $t$ の関係を、うまく式 $\eqref{line}$ の直線によって近似することを考えてみる。

この直線をそのまま赤い点の集まりの上におくと、以下のようになる。

**図表**

あまりうまく $x$ と $t$ の関係を表しているようには見えない。

式 $\eqref{line}$ で表される直線は、$w$ と $b$ が決まると、どのような直線になるかが決定される。
つまり、この $w$ と $b$ の値をうまく決定して、赤い点の集まりにできるだけ沿うような直線を見つけることができれば、新しい $x$ が与えられたときに、$t$ の値がどのような値になりそうかを予測することができそうである。
このとき、未知のデータに対しても精度良く予測が行えることを**汎化性能 (generalizability)** が高いと言う。

また、パラメータ $w$ と $b$ によって特徴づけられた直線の式  $\eqref{line}$ のような、パラメータを使って何らかの計算を行うことで、与えられたデータの特徴や関係性を表すものを、以降簡単に**モデル (model)** と呼ぶことにする（[注釈1](#note1)）。

それでは、$x$ と $t$ の関係をよく表すモデルのパラメータ $w$ と $b$ は、どうやって決定すればよいのだろうか。
先程のように、人が赤い点の集まりを目で見て $x$ と $t$ の関係に当たりをつけ、最適な $w$ と $b$ の値を人手で探り当てるのは、赤い点がもし 3 次元空間や、4 次元、5 次元…といった人間には想像することが難しい高次元空間に散らばっていたら、目で見ることもできないため、困難になる。
そこで、コンピュータにこれらの赤い点のデータを与えて、自動的に最適な $w$ と $b$ を探させようと言うのが、機械学習で行われる代表的な処理のひとつである。

**目的関数**

コンピュータによいパラメータを自動的に見つけてもらうためには、**何がよいパラメータなのか**と言う指標を定義する必要がある。
そのような指標を表す関数を**目的関数 (objective function)** と呼ぶ。

ここで、上の直線の例に戻って考えてみる。
まず、式 $\eqref{line}$ にある $x$ を与えると、$w$ と $b$ を使って $wx + b$ と言う計算が行われる。
その結果を $y$ と表すことにする。
ここで、$x$ を**入力変数 (input variable)**、$y$ を**出力変数 (output variable)** と呼ぶ。
今、上図の赤い点の集まりから 1 点を選び出し、その $x$ 座標の値を式 $\eqref{line}$ に与えたとする。
このとき、式 $\eqref{line}$ に与えられた具体的な $x$ の値を、**入力値 (input value)** と呼ぶ。
そして、パラメータ $w$ と $b$ を用いて計算を行った結果得られる具体的な $y$ の値を、**予測値 (predicted value)** と呼ぶ。
このとき、直線の式ではなく、実際の赤い点の持つ $t$ の値は、この式が予測したい目標の値なので、**目標値 (target value)** と呼ぶ。

目的関数は多くの場合、モデルの予測値と目標値を受け取って、その間の差異を測って返すような関数である。
差異は小さければ小さいほどモデルの予測が当たっていることを意味するため、この場合は目的関数の値を最小にするパラメータを見つけ出すのが目的になる。

**二乗誤差関数**

目的関数の具体例を挙げる。
例えば、適当に赤い点を 1 つ選び、その $x$ 座標が $100$ で、 $t$ 座標が $40$ だったとする。
この値を、$x_1 = 100, t_1 = 40$ のようにおいてみる。
そして、別な点も取り出してきて、同じように座標値 $(x, t)$ を $(x_2, t_2)$ と書くことにする。
同様にして、200 個赤い点を取り出してきたとすると、200 個の $x$ の値 $x_1, x_2, \dots, x_{200}$ と $t_1, t_2, \dots, t_{200}$ が得られる。

この $x_1, x_2, \dots, x_{200}$ から $t_1, t_2, \dots, t_{200}$ を予測するのが目標だった。
つまり、$x_1, x_2, \dots, x_{200}$ が入力値、$t_1, t_2, \dots, t_{200}$ が目標値である。

そして、この 200 個の $x$ の値全てに対して、式 $\eqref{line}$ による予測値 $y$ を計算した結果、$y_1, y_2, \dots, y_{200}$ が得られたとする。

このとき、これらの予測値の正確さを、対応する目標値との間の**差の二乗**によって測るのが、**二乗誤差関数 (squared error function)** と呼ばれるものである。

具体的には、$n$ 個目の予測値を $y_n$、目標値を $t_n$ とすると、以下のような関数である。

$$
\mathcal{l} = (t_n - y_n)^2
$$

これは、$n$ 個目のデータに対する予測値と目標値の差異を表している。
しかし、ある 1 つのデータに対してだけ予測がうまくいっていたとしても、それ以外のデータに対して全くうまく予測できないのであれば、そのモデルが新しい値に対して正確な予測を行うことは困難であると考えられる。
そこで、200 個のデータ全てに渡って、この二乗誤差を足し合わせ、データ数の 200 で割って平均をとったものを考える。

$$
L = \frac{1}{200} \sum_{n=1}^{200} (t_n - y_n)^2
$$

$\sum$ と言う記号は、**総和**を表す。
上の式は、$(t_n - y_n)^2$ の値を、$n = 1$ から順番に $n = 2, n = 3, \dots, n = 200$ まで計算していき、全てを足し合わせ、$200$ で割る、と言うことを意味する。

これは、**平均二乗誤差 (mean squared error)** と呼ばれ、連続値を予測する回帰問題などでよく用いられる代表的な目的関数の 1 つである。
この関数は、予測値と目標値がすべての $n$ において完全に一致するときだけ $0$ になり、それ以外では必ず正の値をとる。
よって、この目的関数の値を最小にする $w$ と $b$ が、求めたい最適なパラメータである。
「よいパラメータとは何か」が定量的に定義できたので、次はコンピュータに解を探索させる方法を考える。

**目的関数の最適化**

ある関数を最小にする入力変数の値を求めることを最適化と言う。この最適化をコンピュータで自動的に行うには、どうすればよいのだろうか。
例えば、以下のような関数があるとする。
横軸が入力の値、縦軸が出力の値である。

**図表**

このとき、関数に適当な値をまず入力してみて、得られた値を使ってその値が小さくなりそうな方向に入力を少し動かす、と言うことを繰り返し行って、関数が最小値をとる入力値を探索する、と言う方法がある。

**機械学習で使われる数学**

このような最適化を行うのに必要になるのが**微分 (differential)** の知識である。
なぜなら、「入力をどちらに動かせば出力が小さな値になりそうか」と言うことを知るためには、対象の関数を微分する必要があるからである。詳細は次章で説明する。

また、初めにあげた赤い点の集まりに最もよく沿うような直線を求める問題では、1 つの値を入力して 1 つの値が出力される関数を考えていたが、複数の値を同時に扱いたいときに必要になるのが、**線形代数 (linear algebra)** の知識である。

さらに、赤い点がもし本当は直線上にぴったり沿うようなデータであったのに、観測時に何らかの理由でノイズが乗ってしまったがために直線の周辺にばらついて出てきているのだとしたら、そのノイズがどの程度の範囲で値のズレを発生させるものなのか、見当をつけておきたくなるかも知れない。
そういったときに必要になるのが、**確率(probability)・統計 (statistics)** の知識である。

この 3 つについて、機械学習の学習に必要となる最低限の知識に絞って以降の 3 章で解説を行う。

それでは、次章はまず微分についてである。

# いまここ

# 微分の基礎

**微分と関数最小化の関係**

前章で微分が目的関数の最小化に役立つと紹介した。本節ではまず具体例を用いてそのことを直感的に理解する。
例として、下図のような下向きにくぼんだ形をした関数がどこで最小値をとるかを探す問題を考える。

**図表**

適当な点 $\theta_{1}$ でこの関数のグラフに接する直線（**接線**）を考える（[注釈1](#note1)）。
仮にこの接線の傾きが $+3$ 、すなわち正の値であったとする。この時、接線は右に進むほど高さが上がり，逆に左に進むほど高さが下がる。
$\theta_{1}$ の周辺では、関数のグラフと接線は非常に近く、両者はほとんど見分けることができない。
すると、関数も接線と同じように $\theta_{1}$ 右に進むと増加し，左に進むと減少していることがわかる。

**図表**

次に、グラフ上の別の点 $\theta_{2}$ においてこのグラフに接する接線を考える。
今度は接線の傾きが $-1$ であるとする。傾きが負のため、接線は右肩下がりの直線である。
グラフは接線と非常に近いため、グラフも $\theta_{2}$ の周辺では、同じように右肩下がりであるとわかる。

**図表**

最後にちょうどグラフの谷となっている点 $\theta_{3}$ を考える。
図を見て分かる通り、関数はこの点で最小値を取る。
一方、点 $\theta_{3}$ でグラフに接する接線は水平、すなわち**傾きが0**である。

これまでの観察をまとめると、接線の傾きと関数の振る舞いには次の関係があることがわかる。

- ある点で接する接線の傾きが正ならば、その点の近くでグラフは右肩上がり（= 左に進むと高さが下がる）
- ある点で接する接線の傾きが負ならば、その点の近くでグラフは右肩下がり（= 右に進むと高さが下がる）
- 関数が最小値をとる点に接する接線の傾きは $0$ である

つまり、関数の最小値をとる点を求める問題では、接線の傾きが $0$ となる点が答えの候補（[注釈2](#note2)）となることがわかる。
本章で説明するように、**微分を用いると接線の傾きを計算することができる**。
このことから、微分が関数の最小化問題に有用なツールであることがわかる。

以降では、微分の定義と微分に関する公式を紹介する。さらに、入力が多変数の関数での微分（偏微分）についても解説する。

## 2 点間を通る直線の傾き

接線の傾きと微分の関係を調べるため、まずは2点を通る直線の傾きを求める問題を考える。

**図表**

直線の傾きは 「$y$ （縦方向）の増加量 / $x$ （横方向）の増加量」で計算できるので、上図の直線の傾き $a$ は、

$$
a = \dfrac{f(x_{2}) - f(x_{1})}{x_{2}-x_{1}}
$$

で求められる。

## 接線の傾き

上図での点 $x_1$ における接線の傾きを求めるために、もう一方の点 $x_2$ を $x_1$ に近づけていく。ただし、 $x_1$ と $x_2$ が完全に同じになってしまうと、$x$ 方向、 $y$ 方向の増加量がどちらも $0$ になってしまうため、傾きは $0/0$ で計算することができない。
そこで 2 点は異なる点でありつつ、 $x_2$ を限りなく $x_1$ に近づけていった時、直線の傾きがどのように振る舞うかを見る必要がある。これを数式的に表現するには、**極限**の考えが必要になる。

極限では、変数がある値に限りなく近づくとき、その変数によって記述される関数がどのような値に近づくかを考える。
関数 $f$ に対し、$h$ と言う変数を $a$ に近づけていったときの $f(h)$ が近づく値を $\lim$ と言う記号を用いて

$$
\displaystyle \lim _{h\rightarrow a} f(h)
$$

と書く。例えば、 $h$ を限りなく $0$ に近づけた時に、 $3h$ も限りなく $0$ に近づいていく。
従って

$$
\displaystyle \lim _{h\rightarrow 0} 3h=0
$$

である。もっと一般に $n$ を自然数、 $c$ を定数として、

$$
\displaystyle \lim _{h\rightarrow a} c h^n=c a^n
$$

が成立する。これだけ見ると単に関数 $\lim _{h\rightarrow a} f(h)$ は $h$ に $a$ を代入した値 $f(a)$ のように思えるかも知れない。しかし、今考えている直線の傾きの場合、そのような代入操作を行うと先程のように $0/0$ の形が現れてしまうため、単純な代入では極限を求めることはできない。
極限の計算方法は後ほど詳しく解説する。

それでは、下図のある点 $x$ における接線の傾き $a$ を求めていこう。

**図表**

2点を通る直線の傾きの式と極限を組み合わせて、接線の傾きを求めることができる。

**図表**

はじめに、 $x$ から $h$ だけ離れた点 $x + h$ を考え、2点を通る直線の傾きを求めてみる。
次に $h$ を $0$ に限りなく近づけていけば、1点 $x$ で接する接線を考えることができる。
これを式でみると

$$
\begin{aligned}
a
&= \lim_{h \rightarrow 0} \frac{f(x + h) - f(x)}{(x + h) - x} \\
&= \lim_{h \rightarrow 0} \frac{f(x + h) - f(x)}{h} \\
\end{aligned}
$$

となる。よく見るとこの式は $x$ を決めるごとにある1つの値を定めている、すなわちこの式は $x$ の関数である（$h$ は $h\to 0$ の極限を取っているので $h$ の関数にはなっていないことに注意する）。
この式を $f$ の **導関数 (derivative)**と呼び、 $f'(x)$ と書く。すなわち、

$$
f'(x)= \lim_{h \rightarrow 0} \frac{f(x + h) - f(x)}{h}
$$

である。導関数を求めることを**微分(differentiation)**すると言う。
記号の使い方として、 $f'(x)$ を

$$
\frac{d}{dx}f (x)
$$
または
$$
\frac{df}{dx} (x)
$$

と書いても構わない。
この $d$ と言う記号は増分をとる操作を表しており、例えば $dx$ は $x$ の変化量を表す。
この記法は煩雑であるが、$x, y$ など変数が複数ある場合、 どの変数で微分しているかが明確になるため、表現を正確にすることができる。

## 微分の公式

ある関数の導関数を計算するには、導関数の定義通りに計算するのが最も愚直な方法である．
しかし、これから紹介する種々の公式を組み合わせることで、わざわざ定義に戻らなくても、複雑な関数の導関数を計算できる。
以下では、 $c$ は定数、 $x$ は変数を表す。

まずはじめに、以下の 3 つの公式を紹介する。

$$
\begin{align}
\left( c\right)^{'} &= 0 \\
\left( x\right)^{'} &= 1\\
\left( x^{2}\right)^{'} &= 2x
\end{align}
$$

1つ目の左辺は定数関数 $f(x) = c$ を $x$ で微分した導関数を表している。
定数関数のグラフを書くと $x$ 軸に平行になるため、どの点で接線を引いてもその傾きは $0$である（グラフと接線は同一の直線となる）。これは導関数は 0 であることを意味する。これが 1 つ目の式の図形的な理解である。
同様に2つ目の公式は 「$y=x$ のグラフではどの点で接線を引いても傾きが1」であることを意味する（この場合もグラフと接線は同一の直線である）。
極限の扱いに慣れるために、3番目の公式を証明する。導関数の定義から左辺は

$$
\displaystyle \lim _{h\to 0} \frac{(x+h)^2 - x^2}{(x+h) - x}
$$
である。これは

$$
\begin{align}
\lim _{h\to 0} \frac{(x+h)^2 - x^2}{(x+h) - x} = \lim _{h\to 0} \frac{2xh + h^2}{h} = \lim _{h\to 0} (2x + h)
\end{align}
$$

と計算できる。ここで $h\to 0$ 、すなわち $h$ を限りなく $0$ に近づけると、 $2x + h$ は $2x$ に限りなく近づいていく。従って、 $\left( x^{2}\right)^{'} = 2x$ が導かれた。

以下の公式も頻繁に利用する。

$$
\begin{align}
\left( x^{n} \right)^{'} &= nx^{n-1} \\
\left( e^{ax} \right)^{'} &= ae^{ax}
\end{align}
$$

ここで、$a$ は定数、 $e$ は**自然対数の底**、もしくは **ネイピア数** と呼ばれる特別な定数で、およそ $2.71828\cdots$ である。 $1$ つ目の公式で $n=1, 2$とすると、本節の最初に紹介した $x$, $x^2$ の微分の公式に帰着されることに注意する。
$e^{ax}$ は $\exp(ax)$ のように表記されることがよくある。その表記を用いると最後の公式は

$$
\bigl( \exp(ax) \bigr)^{'} = a\exp(ax)
$$

とも書ける。

## 線形性

微分は**線形性**と言う性質を持っている。
それがどのような性質なのか、具体例を挙げて見ていこう。
微分には線形性と言う性質によって、

$$
(3x)' = 3 \times (x)'
$$

のように定数項を微分の演算の外側に出すことができる。
また、

$$
\left( 3x^{2} + 4x - 5 \right)' = \left( 3x^{2} \right)' + \left( 4x \right)' - \left( 5 \right)'
$$

のように、加算や減算はそれぞれ項ごとに独立に微分の演算を行うことができる。
この 2 つの特性を合わせて線形性と呼ぶ。

もう少し微分の計算を練習してみる。

$$
\begin{aligned}
\left( 3x^{2} + 4x + 5 \right)' &= \left( 3x^{2} \right)' + \left( 4x \right)' - \left( 5 \right)' \\
&= 3 \times \left( x^{2} \right)' + 4 \times \left( x \right)' - 5 \times \left( 1 \right)' \\
&= 3 \times 2x + 4 \times 1 - 5 \times 0  \\
&= 6x + 4
\end{aligned}
$$

この線形性に関しては、下記のように公式としてまとめることができる。

$$
\begin{align}
\left( cf(x) \right)^{'} &= c f'(x) \\
\left( f(x) + g(x) \right)^{'} &= f^{'}(x) + g^{'}(x) \\
\end{align}
$$

2 つの関数の積の形で書かれている関数に関しては次の公式が成り立つ。

$$
\bigl( f(x) g(x) \bigr)^{'} = f^{'}(x)g(x) + f(x)g^{'}(x)
$$

関数 $f$ の導関数と関数 $g$ の導関数がわかれば、関数 $fg$ を計算できることがわかる。

## 合成関数の微分

関数 $y = f(x)$ と $z = g(y)$ の**合成**とは $f$ を適用したあとに $g$ を適用する関数、すなわち $z  = g(f(x))$ のことを指す。
ディープラーニングで用いるニューラルネットワークは、層を何層も重ねて複雑な関数を表現する。各々の層を 1 つの関数とみなすと、ニューラルネットワークは多くの関数（層）を合成した**合成関数**と見ることができる。
合成関数の微分を考える時には次に紹介する公式（合成関数の微分の公式）が有用である。
この公式は**連鎖律 (chain rule)** とも呼ばれている。
連鎖律は合成関数を微分を簡単に計算するための公式と言うだけではなく、ニューラルネットワークの訓練方法である誤差逆伝播法を理解する上で本質的な役割を果たす。

簡単な例として、

$$
\left\{ (3x + 4)^{2} \right\}'
$$

を計算することを考える。
この式は、 $3x+4$ と言う内側の部分と $(\cdot)^{2}$ と言う外側の部分で構成されている。
この式を $(9x^2 + 24x + 16)'$ のように展開してから微分を計算してもよいのだが、3乗や4乗とべき数が増えると式を展開するのが大変になる。
ここで役に立つ考え方が合成関数の微分である。
合成関数の微分は、内側の微分と外側の微分をそれぞれ行い、その結果をかけ合わせることで求めることができる。
外側の微分の際には関数の引数を入力とみなし、その入力についての微分を計算する。

それでは、具体的にこの $(3x+4)^2$ と言う関数の微分を考えてみる。
まず内側の関数を $u = (3x+4)$ とおいて、

$$
\left\{ (3x + 4)^{2} \right\}' = (u^{2})'
$$

と見る。ここで、 $(\cdot)'$ をもう少し厳密に考える必要が出てくる。
今変数は $x$, $u$ の2つあるため、 $(\cdot)'$ と言う表記では、 $x$ で微分しているのか $u$ で微分しているのかの区別がつかない。
そこで、多少複雑に見えるが、先程紹介した $d$ を使った記法を用いて微分する変数を明示する。

合成関数の微分を公式としてまとめると次のようになる。

$$
\frac{d}{dx} f(g(x)) = \frac{df(u)}{du}\frac{du}{dx}
$$

ここで $u = g(x)$ である。

公式を見るよりも実際の適用例を見た方が理解しやすいかも知れない。
合成関数の微分の公式を用いて、先程の $(3x+4)^2$ の微分を計算すると次のようになる。
2行目で合成関数の微分の公式を利用していることに注目する。

$$
\begin{aligned}
\left\{ (3x + 4)^{2} \right\}' &= \frac{d}{dx} \left\{ (3x + 4)^{2} \right\} \\
&= \frac{du}{dx} \frac{d}{du} (u^2) \\
&= \frac{d}{dx} (3x + 4) \cdot \frac{d}{du} (u^{2}) \\
&= 3 \cdot 2u   \\
&= 6u = 6(3x + 4) = 18x + 24 \\
\end{aligned}
$$

気になる人は、 $(3x + 4)^2$ を展開してから各項を微分した場合と結果が一致していることを確かめてみる。

## 偏微分

機械学習では、1つの入力変数 $x$ から出力変数 $y$ を予測するケースは稀であり、多くの場合、複数の入力変数 $x_1, x_2, \dots, x_M$ を用いて $y$ を予測する**多変数関数**が扱われる。
例えば、家賃を予測する場合、部屋の広さだけではなく、駅からの距離や周辺の犯罪発生率なども同時に考慮した方がより正確に予測ができると期待される。
複数の入力 $x_1, x_2, \dots, x_M$ をとる関数 $f(x_1, x_2, \dots, x_M)$ を多変数関数と呼ぶ。
この多変数関数において、ある入力 $x_m$ にのみ注目して微分することを **偏微分** とよび、

$$
\frac{\partial}{\partial x_{m}} f(x_1, x_2, \dots, x_M)
$$

と表す。微分を意味する記号が、 $d$ から $\partial$ に変わっている。こうすると、 $\frac{\partial}{\partial x_m}$ は $x_m$ 以外を定数と考え、 $x_m$ にのみ着目して微分を行うと言う意味となる（[注釈3](#note3)）。

以下の例で具体的な計算の流れを確認する。

$$
\begin{aligned}
\frac{\partial}{\partial x_1}
\left( 3x_1+4x_2 \right)
&= \frac{\partial}{\partial x_1}
\left( 3x_1 \right) + \frac{\partial}{\partial x_1} \left( 4x_2 \right) \\
&= 3 \times \frac{\partial}{\partial x_1} \left( x_1 \right) + 4 \times \frac{\partial}{\partial x_1} x_2 \\
&= 3 \times 1 + 4 \times 0 \\
&= 3
\end{aligned}
$$

偏微分でも微分と同じ公式を適用できる。今回のケースでは、 $x_1$ にだけ着目しており、 $x_2$ は定数として扱かっている。そのため、上式の 2 行目から 3 行目で $x_2$ を $x_1$ で偏微分した値を $0$ としている（定数の微分は $0$ であったことを思い出す）。

**注釈 1**

ここで考えている関数のグラフでは、グラフ上のどの点を取ってもその点で接する接線がただ1本だけ引ける状況を考えている。例えば関数のグラフが谷の部分で「尖った」形をしていると，谷の底で複数の接線が引けてしまう。ここではそのようなケースは考えず、関数のグラフは図のような「滑らか」なカーブになっている場合をイメージする。

[▲上へ戻る](#ref_note1)

**注釈 2**

今は関数のグラフの「谷」を考えたが、「山」でも同様に接線の傾きが $0$ となるため、ある点での接線の傾きが $0$ だからと言って、必ずしも関数がその点で最小値をとるとは限らない。

[▲上へ戻る](#ref_note2)

**注釈 3**

入力変数が他の入力変数と独立でない場合は定数と考えることはできない。しかし本資料ではそのようなケースは出てこない。

[▲上へ戻る](#ref_note3)

```python

```

# 線形代数の基礎

機械学習の理論では線形代数で用いられる概念が多く登場する。
これらの概念を利用することで、複数の値や変数をまとめて扱うことができるようになり、数式を簡潔に表現できるようになる。
本章では、特に以下の概念を順番に紹介する

- スカラ・ベクトル・行列・テンソル
- ベクトル・行列の演算（加減算・スカラ倍・内積・行列積）
- 特別な行列（単位行列・逆行列）
- 多変数関数（線形結合，二次形式）とその微分

## スカラ・ベクトル・行列・テンソル

始めに、スカラ、ベクトル、行列、テンソルと言う 4 つの言葉を解説する。

**スカラ (scalar)** は、2.5、-1、$\sqrt{2}$、$\pi$といった 1 つの値もしくは変数のことを指す。スカラは温度や身長といった単一の数量を表す。スカラ変数を表すには

$$
x, \ y,\  M,\  N
$$

のような文字を利用するのが一般的である。

$2.4+3.2i$ のような複素数でも、値が 1 つならばスカラ（複素数のスカラ）と呼ぶが、本資料では特に明示しなければ実数のスカラを扱う。後述するベクトル、行列、テンソルについても同様である。

$x$ が実数のスカラであることをしばしば「$x\in \mathbb{R}$」と書く。

$\mathbb{R}$ は実数のスカラからなる集合を表し、「$A\in B$」は「$A$ は $B$ に属する」と言う意味である。従って、$x\in \mathbb{R}$ で「$x$ は実数のスカラからなる集合に属する」、すなわち「$x$ は実数のスカラである」と解釈できる。

**ベクトル (vector)** は、スカラを 1 方向に並べたものである。例えば、

$$
{\bf x}=\begin{bmatrix}
x_{1} \\
x_{2} \\
x_{3}
\end{bmatrix}, \
{\bf y}=\begin{bmatrix}
y_{1} \\
y_{2} \\
\vdots \\
y_{N}
\end{bmatrix}
$$

のように表す。ベクトルを構成するスカラ達（$x_1$ や $y_2$ など）のことを**要素**や**成分**と呼ぶ。
ベクトルを表すのに用いられる文字は、スカラと区別しやすいよう太字とするのが一般的である。
上の 2 つの例のように、その要素を**縦方向に並べたものは列ベクトル**と呼ぶ。
一方、

$$
{\bf z}=\begin{bmatrix}
z_{1} & z_{2} & z_{3}
\end{bmatrix}
$$

のように、要素を**横方向に並べたものは行ベクトル**と呼ぶ。

本資料では、特に明示しない限り、**単にベクトルと表現した場合には列ベクトルを指すもの**とする。

ベクトルに含まれるスカラの数のことを、そのベクトルの**次元**と呼ぶ。
例えば、${\bf x}$は3次元の列ベクトル、${\bf z}$ は3次元の行ベクトルである。
スカラの場合と同様に、ベクトル ${\bf x}$ が$N$次元のベクトルで、ベクトルを構成するスカラが実数であることを、数式を用いて「${\bf x}\in \mathbb{R}^N$」とも書く。

**行列 (matrix)** は同じサイズのベクトルを複数個並べたものである。例えば、

$$
{\pmb X} =
\begin{bmatrix}
x_{11} & x_{12} \\
x_{21} & x_{22} \\
x_{31} & x_{32}
\end{bmatrix}
$$

は行列の一例である。行列は大文字、または大文字の太文字で表記することでスカラやベクトルと区別する。
行列の形（サイズ）は行数と列数で表現する。
例えば、上に挙げた ${\bf X}$ は行ベクトルが 3 つ並んだものと見ることができる。
そのため、 ${\bf X}$ の行数は 3 である。
一方、見方を変えると ${\bf X}$ は列ベクトルが 2 つ並んだものと見ることもできるので、 ${\bf X}$ の列数は 2 である。
そこで、 ${\bf X}$ を「 3 行 2 列の行列」と呼ぶ。
「サイズが $(3, 2)$ である行列」や「サイズが $3\times 2$ の行列」と呼んでも構わない。
$N$ 次元の列ベクトルはサイズが $(N, 1)$ の行列、 $N$ 次元の行ベクトルはサイズが $(1, N)$ の行列と見ることができる。
スカラ、ベクトルの場合と並行して、行列 ${\bf X}$ のサイズが $(N, M)$ であり、各要素が実数であることを、「${\bf X} \in \mathbb{R}^{N \times M}$」 とも書く。例えば、先程の ${\bf X}$ については ${\bf X}\in \mathbb{R}^{3\times 2}$ である。

**テンソル (tensor)** はベクトルや行列を一般化した概念である。

例えば、ベクトルは 1 方向に、行列は 2 方向にスカラが並んでいる。

これは「ベクトルは 1 階のテンソルで、行列は 2 階のテンソルである」であることを意味する。

この考え方をさらに進めて、行列を奥行き方向にさらに並べたものを3階のテンソルと呼ぶ。

例えば、カラー画像をデジタル表現する場合、1 枚の画像は RGB (Red Green Blue) の3枚のレイヤー（チャンネルと呼ぶ）を持つのが一般的である。

各チャンネルは行列として表され、その行列がチャンネル方向に複数積み重なっているため、画像は 3 階テンソルとみなすことができる。

3 階のテンソルは、特定の要素を指定するのに「上から 3 番目、左から 2 番目、手前から 5 番目」のように整数（インデックス）を3個必要とする。

同様に、4 次元以上の場合でも、$N$ 次元にスカラを並べたもの（つまり、要素を指定するのに $N$ 個のインデックスが必要なもの）を $N$ 階のテンソルと言う。例えば、多くのディープラーニングフレームワークでは、複数枚の画像の集まりを「画像のインデックス1つ」+「各画像のインデックス 3 つ（幅、高さ、チャンネル）」の 4 階テンソルとして表現する。

前述のようにベクトルや行列はテンソルの一種とみなすことができるが、本資料では単に「テンソル」と言った場合は3階以上のテンソルを指す。

### 変数の形と字体の関係

多くの教科書（特に線形代数の教科書）では、変数を一目見てその型が何かがわかるように、特定の形（ベクトル、行列など）の変数には特定の字体を用いると言う工夫がされている。
本資料に限らず、数式を追う時には変数の字体を見て、その変数の形を意識するのがおすすめである。
変数の形と字体の対応関係は教科書によって流派があるが、以下にその一例を紹介する（本資料もこの規約に従う）。

|  字体  | 小文字         | 大文字         |
|:------:|:--------------:|:--------------:|
| 細字   | スカラの変数 ($a, b$ など) | スカラの定数 ($A, B$ など) |
| 太字   | ベクトル (${\bf x}, {\bf y}$ など)       | 行列、テンソル (${\bf A}, {\bf B}$ など) |

# いまここ 2

### 加算・減算・スカラ倍

次に、ベクトル、行列、テンソルの演算について解説する。

**加算（足し算）**及び**減算（引き算）**は同じサイズのベクトル同士、行列同士、テンソル同士の間だけで成立する。

以下に、行列およびベクトル同士の加算を具体例で示す。

**ベクトル同士の加算**
$$
\begin{bmatrix}
1 \\
2 \\
3
\end{bmatrix}+\begin{bmatrix}
4 \\
5 \\
6
\end{bmatrix}=\begin{bmatrix}
1 + 4 \\
2 + 5 \\
3 + 6
\end{bmatrix}=\begin{bmatrix}
5 \\
7 \\
9
\end{bmatrix}
$$

**行列同士の加算**
$$
\begin{bmatrix}
1 & 2 & 3 \\
4 & 5 & 6
\end{bmatrix}+\begin{bmatrix}
7 & 8 & 9 \\
10 & 11 & 12
\end{bmatrix}=\begin{bmatrix}
1+7 & 2+8 & 3+9 \\
4+10 & 5+11 & 6+12
\end{bmatrix}=\begin{bmatrix}
8 & 10 & 12 \\
14 & 16 & 18
\end{bmatrix}
$$

このように、加算、減算ではベクトル（行列/テンソル）の同じ位置にある要素同士に演算を行う。
このような計算は、**要素ごとの (element-wise)** 計算とも呼ばれている。
ベクトル（行列/テンソル）のサイズが異なる場合、計算が定義できないことに注意する。

**スカラ倍**とはベクトル、行列、テンソルにスカラを掛ける演算である。
例えば、スカラ $k$ に対し、「ベクトル ${\bf x}$ の $k$ 倍」とは、ベクトルの各要素に$k$を掛ける操作である。
行列やテンソルの場合も同様に要素ごとに同じスカラ$k$を掛けます。
言葉で説明するよりも以下の具体例を見る方がわかりやすいかもしれない。

**ベクトルのスカラ倍**
$$
10
\begin{bmatrix}
1 \\
2 \\
3
\end{bmatrix}=\begin{bmatrix}
10 * 1 \\
10 * 2 \\
10 * 3
\end{bmatrix}=\begin{bmatrix}
10 \\
20 \\
30
\end{bmatrix}
$$

**行列のスカラ倍**
$$
10
\begin{bmatrix}
1 & 2 & 3 \\
4 & 5 & 6
\end{bmatrix}=\begin{bmatrix}
10 * 1 & 10 * 2 & 10 * 3 \\
10 * 4 & 10 * 5 & 10 * 6
\end{bmatrix}=\begin{bmatrix}
10 & 20 & 30 \\
40 & 50 & 60
\end{bmatrix}
$$

スカラ倍を行う前後でベクトル（行列/テンソル）のサイズは変化しないことに注意する。

### 内積

同じサイズの2つのベクトルには、**内積 (inner product)** と言う演算が定義できる。
これは、それぞれのベクトルの同じ位置に対応する要素同士を掛け、それらを足し合わせる計算である。
${\bf x}$ と ${\bf y}$ の内積は ${\bf x}\cdot {\bf y}$ で表されます。
例えば、以下の例では 3 次元のベクトルの内積を計算している。

$$
\begin{aligned}& \begin{bmatrix}
1 & 2 & 3
\end{bmatrix} \cdot \begin{bmatrix}
4 \\
5 \\
6
 \end{bmatrix} = 1 \times 4 + 2 \times 5  + 3 \times 6 = 32 \end{aligned}
$$

2 つのベクトルの内積はスカラになることに注意する。
上の例で示しているように、内積を考える時には 1 つ目のベクトルを行ベクトル（つまり、スカラを横に並べたベクトル）と思うと都合がよい。これは次に説明する行列積に関連する。このように書いた場合には内積を表す $\cdot$ は省略できる。

### 行列積

行列の乗算には、**行列積**、**外積**、**要素積（アダマール積）**など複数の方法がある。
ここではそのうち、線形代数や機械学習の多くの問題で登場する**行列積**について説明する。
以降では明示しない限り、「行列の掛け算」と言ったときには行列積を指すこととする。

行列 ${\bf A}$ と行列 ${\bf B}$ の行列積は ${\bf AB}$ と書き 、${\bf A}$ の各行と ${\bf B}$ の各列の内積を並べたものとして定義されます。
例えば、行列 ${\bf A}$ の 1 行目の行ベクトルと、行列 ${\bf B}$ の 1 列目の列ベクトルの内積の結果は、${\bf A}$ と ${\bf B}$ の行列積の結果を表す行列 ${\bf C}$ の 1 行 1 列目に対応する。

**図表**

内積が定義される条件はベクトルのサイズが等しくなければならないでした。ここでもそれが成り立たなければならない。具体的には、${\bf A} \in \mathbb{R}^{N \times M}$, ${\bf B} \in \mathbb{R}^{O \times  P}$ の時、${\bf A} {\bf B}={\bf C}$ の行列積を定義するためには、${\bf  A}$ の**列数** $M$ と ${\bf B}$ の**行数**  $O$ が一致する必要がある（[注釈1](#note1)）。
つまり、

$$
M = O
$$

でなければならない。
そして、結果の行列 ${\bf C}$ の行数と列数は ${\bf A}$ の行数 $N$ と ${\bf B}$ の列数 $P$ とそれぞれ等しくなる。
すなわち、${\bf C} \in \mathbb{R}^{N \times P}$ である。

2 つの $N$ 次元ベクトル ${\bf x}, {\bf y}$ の内積は、 ${\bf x}$ をサイズ $(1, N)$ の行列（すなわち行ベクトル），${\bf y}$ をサイズ $(N, 1)$ の行列（すなわち列ベクトル）とみなして行列積を行うことと考えることができる。
2 つのベクトルの行列積はサイズが $(1, 1)$ の行列、すなわちスカラとなる。これは 2 つのベクトルの内積の結果がスカラとなることと一致している。

**図表**

行列積は${\bf AB}$ と ${\bf BA}$ が等しいとは限らないと言う点でスカラの掛け算と大きく異なる。例えば、

$$
{\bf A} = \begin{bmatrix}
1 & 2 \\
3 & 4
\end{bmatrix},
{\bf B} = \begin{bmatrix}
5 & 6 \\
7 & 8
\end{bmatrix}
$$

とすると，

$$
{\bf AB} = \begin{bmatrix}
1 & 2 \\
3 & 4
\end{bmatrix}
\begin{bmatrix}
5 & 6 \\
7 & 8
\end{bmatrix} =
\begin{bmatrix}
1 * 5 + 2 * 7 & 1 * 6 + 2 * 8 \\
3 * 5 + 4 * 7 & 3 * 6 + 4 * 8
\end{bmatrix} =
\begin{bmatrix}
19 & 22 \\
43 & 50
\end{bmatrix}
$$

$$
{\bf BA} = \begin{bmatrix}
5 & 6 \\
7 & 8
\end{bmatrix}
\begin{bmatrix}
1 & 2 \\
3 & 4
\end{bmatrix} =
\begin{bmatrix}
5 * 1 + 6 * 3 & 5 * 2 + 6 * 4 \\
7 * 1 + 8 * 3 & 7 * 2 + 8 * 4
\end{bmatrix} =
\begin{bmatrix}
23 & 34 \\
31 & 46
\end{bmatrix}
$$

となり、 ${\bf AB} \not = {\bf BA}$ である。
掛け算の順序の違いを明示的に表現する場合、行列 ${\bf A}$ に行列 ${\bf B}$ を左から掛けること（ ${\bf BA}$ の計算）を行列 ${\bf B}$ を行列 ${\bf A}$ に**左乗**すると言い、右から掛ける場合は**右乗**すると言う。

${\bf A}$ と ${\bf B}$ の選び方によっては ${\bf AB}$ と ${\bf BA}$ が等しくなる場合もある。
例えば、

$$
{\bf A} = \begin{bmatrix}
1 & 2 \\
3 & 4
\end{bmatrix},
{\bf B} = \begin{bmatrix}
3 & 0 \\
0 & 3
\end{bmatrix}
$$

とすると、

$$
\begin{bmatrix}
1 & 2 \\
3 & 4
\end{bmatrix}
\begin{bmatrix}
3 & 0 \\
0 & 3
\end{bmatrix} =
\begin{bmatrix}
3 & 0 \\
0 & 3
\end{bmatrix}
\begin{bmatrix}
1 & 2 \\
3 & 4
\end{bmatrix} =
\begin{bmatrix}
3 & 6 \\
9 & 12
\end{bmatrix}
$$

となり、 ${\bf AB}$ と ${\bf BA}$ は一致する。ここで述べている注意は 「**どんな** ${\bf A}, {\bf B}$ でも${\bf AB} = {\bf BA}$ が成立する」と言う主張は正しくないことを意味している。

それでは、行列の計算条件も確認しながら、下記の 3 つの練習問題の計算を行う。

$$
\begin{aligned}
&\left( 1\right)
\begin{bmatrix}
1 & 2
\end{bmatrix}
\begin{bmatrix}
3 \\
4
\end{bmatrix}\\
&\left( 2\right)
\begin{bmatrix}
1 & 2 \\
3 & 4
\end{bmatrix}\begin{bmatrix}
5 \\
6
\end{bmatrix}\\
&\left( 3\right)
\begin{bmatrix}
1 & 2
\end{bmatrix}\begin{bmatrix}
3 & 4 \\
5 & 6
\end{bmatrix}\begin{bmatrix}
3 \\
1
\end{bmatrix}
\end{aligned}
$$

こちらが解答である。

$$
\begin{aligned}
&\left( 1\right)
\begin{bmatrix}
1 & 2
\end{bmatrix}\begin{bmatrix}
3 \\
4
\end{bmatrix} = 1\times 3 + 2 \times 4 = 11\\
&\left( 2\right)
\begin{bmatrix}
1 & 2 \\
3 & 4
\end{bmatrix}\begin{bmatrix}
5 \\
6
\end{bmatrix} = \begin{bmatrix}
1 \times 5 + 2 \times 6 \\
3 \times 5 + 4 \times 6
\end{bmatrix} = \begin{bmatrix}
17 \\
39
\end{bmatrix}\\
&\left( 3\right)
\begin{bmatrix}
1 & 2
\end{bmatrix}\begin{bmatrix}
3 & 4 \\
5 & 6
\end{bmatrix}\begin{bmatrix}
3 \\
1
\end{bmatrix}
=\begin{bmatrix}
1 & 2
\end{bmatrix}\begin{bmatrix}
3 \times 3 + 4 \times 1 \\
5 \times 3 + 6 \times 1
\end{bmatrix} = \begin{bmatrix}
1 & 2
\end{bmatrix}\begin{bmatrix}
13 \\
21
\end{bmatrix}
= 1 \times 13 + 2 \times 21
=55
\end{aligned}
$$

このような計算は、機械学習の基礎を学習していく過程でよく登場する。行列積では、演算前と後の行数・列数の変化に注意する。

### 行列積によるベクトル・行列のサイズ変化

行列の前後では行列の形が変化する。
具体的にはサイズが $(L, M)$ と $(M, N)$ の行列の行列積の結果はサイズが $(L, N)$ の行列となる。
先ほどの 3 つの練習問題では、行列やベクトルの形・サイズがどのように変化していたかを確認してみる。

**図表**

特に (3) では、一番左端のベクトルと、真ん中の行列の乗算結果が、行ベクトルであるため、サイズの変化が (1) と同じケースに帰着することに注意する。

また、例えば $(3, 1)$ の行列のようにある次元のサイズが 1 となった場合、その次元を削除する場合がある。例えば (2)の計算結果はサイズが $(2, 1)$ の行列であるが、これは2次元のベクトルとして扱えます。同様に、 (1), (3) の答えはサイズ $(1, 1)$ の行列であるが、スカラとみなすことができる。このようにサイズが 1 になった次元をつぶす操作をしばしば `squeeze` と呼ぶ。

### 転置

ベクトルは縦方向に要素が並んだ列ベクトルを基本としていましたが、横方向に要素が並んだ行ベクトルを使いたい場合もある。そこで列ベクトルを行ベクトルに、行ベクトルを列ベクトルに変換する操作を**転置 (transpose)** と呼ぶ。転置はベクトルの右肩に ${\rm T}$ と書くことで表す。例えば、 ${\bf x}$ が 3 次元のベクトルならば、

$$
{\bf x}
=\begin{bmatrix}
1 \\
2 \\
3
\end{bmatrix}, \
{\bf x}^{\rm T} = \begin{bmatrix} 1 & 2 & 3 \end{bmatrix}
$$

である。
転置は行列に対しても定義できる。例えば、

$$
{\bf X}
=\begin{bmatrix}
1 & 4 \\
2 & 5 \\
3 & 6
\end{bmatrix}, \
{\bf X}^{\rm T}=\begin{bmatrix}
1 & 2 & 3 \\
4 & 5 & 6
\end{bmatrix}
$$

である。行列に対する転置では、行と列が入れ替わるため、サイズが $(N, M)$ だった行列は、転置するとサイズが $(M, N)$ の行列となる。つまり、 $i$ 行 $j$ 列目の値が転置後には $j$ 行 $i$ 列目の値になる。転置の公式として次を覚えておく。

$$
\begin{aligned}
&\left( 1\right) \ \left( {\bf A}^{\rm T} \right)^{\rm T} = {\bf A} \\
&\left( 2\right) \ \left( {\bf A}{\bf B} \right)^{\rm T} = {\bf B}^{\rm T}{\bf A}^{\rm T}\\
&\left( 3\right) \ \left( {\bf A}{\bf B}{\bf C} \right)^{\rm T} = {\bf C}^{\rm T}{\bf B}^{\rm T}{\bf A}^{\rm T}
\end{aligned}
$$

転置を用いると、 2 つの列ベクトル ${\bf x}$, ${\bf y}$ の内積 ${\bf x}\cdot {\bf y}$ は、行列積を用いて ${\bf x^{\rm T} y}$ と書けることに注意する。

### 単位行列

スカラ値の $1$ は、 $10 \times 1 = 10$ のように、任意の数を $1$ に乗じても値が変化しないと言う性質を持ちます。行列の演算において、これと同様の働きをする行列が**単位行列 (identity matrix, unit matrix)** である（[注釈2](#note2)）。
単位行列は

$$
{\bf I} =
\begin{bmatrix}
1 & 0 & \cdots  & 0 \\
0 & 1 & \cdots  & 0 \\
\vdots & \vdots & \ddots & \vdots  \\
0 & 0 & \cdots  & 1
\end{bmatrix}
$$

と言う形をしており、記号 ${\bf I}$ で表すのが一般的である。行列の斜めの要素を**対角要素**とよび、それ以外の要素を非対角要素とよびます。単位行列は、対角要素が全て $1$ で、非対角要素が全て $0$ であるような **正方行列**（行数と列数が等しい行列）である。例えば、$2 \times 2$ の単位行列は、

$$
{\bf I} =
\begin{bmatrix}
1 & 0 \\
0 & 1
\end{bmatrix}
$$

であり、$3 \times 3$の単位行列は、

$$
{\bf I} =
\begin{bmatrix}
1 & 0 & 0 \\
0 & 1 & 0 \\
0 & 0 & 1
\end{bmatrix}
$$

である。行列のサイズを明示したい場合には、 $I_n$ （ $n \times n$ の単位行列の意味）と添字でサイズを表記することがある。

単位行列はサイズが等しい任意の正方行列 ${\bf A}$ に対して以下の計算が成立する。

$$
\begin{aligned}
{\bf A}{\bf I} &= {\bf A} \\
{\bf I}{\bf A} &= {\bf A}
\end{aligned}
$$

適当な行列で、単位行列を掛けても元の行列と値が変わらないことを確認してみる。

$$
\begin{aligned}
\begin{bmatrix}
1 & 2 \\
3 & 4
\end{bmatrix}
\begin{bmatrix}
1 & 0 \\
0 & 1
\end{bmatrix}
&=
\begin{bmatrix}
1 \times 1 + 2 \times 0 & 1 \times 0 + 2 \times 1 \\
3 \times 1 + 4 \times 0 & 3 \times 0 + 4 \times 1
\end{bmatrix} \\
&=
\begin{bmatrix}
1 & 2 \\
3 & 4
\end{bmatrix}
\end{aligned}
$$

計算結果から分かる通り、元の行列と全ての要素が一致しました。
${\bf I}$ を左から掛けても同様の結果となることを確かめてみる。

### 逆行列

$0$ でないスカラ $x$ には、 逆数 $x^{-1}$ を考えることができる。
行列で逆数に対応するものが **逆行列 (inverse matrix)** である。

厳密な定義は次の通りである。行列 ${\bf A}$ に対し、 ${\bf AB} = {\bf I}$ , ${\bf BA} = {\bf I}$ を満たす行列 ${\bf B}$ のことを ${\bf A}$ の逆行列 と言う。
このような条件を満たす行列 ${\bf B}$ は 行列 ${\bf A}$ によって存在したり存在しなかったりする。
しかし、もし ${\bf A}$ に対しこの条件を満たす行列が存在するならば、そのような行列はただ 1 つであることが知られている。
そこで、行列 ${\bf A}$ の逆行列を ${\bf A}^{-1}$ と書く。

逆行列の定義から、

$$
\begin{aligned}
{\bf AA}^{-1} = {\bf I} \\
{\bf A}^{-1}{\bf A} = {\bf I}
\end{aligned}
$$

が成立することに注意する。ここで、 ${\bf I}$ は単位行列である。

逆行列が存在するような行列のことを**正則行列**と呼ぶ。
正則行列となるには少なくとも行列積 ${\bf AA^{-1}}$ と ${\bf A^{-1}A}$ の両方が定義されていなければならない。
これは ${\bf A}$ は正方行列（つまり、行数と列数が同じ行列）であることを意味する （なぜか考えてみる）。
しかし、 ${\bf A}$ の行数と列数が同じであるからと言って、常に ${\bf A}$ が正則行列とは限らない。
行列が正則であるための条件に関する詳細な説明はここでは省略する。

サイズが $2 \times 2$ や $3 \times 3$ といった小さな行列の場合には、手計算でも可能な逆行列計算の方法が知られているが、機械学習ではより大きなサイズの行列（ $1000 \times 1000$ など）を扱うことがあり、そういった大きな行列の逆行列を効率的または近似的にコンピュータを使って計算する手法が研究されている。

### 線形結合と二次形式

機械学習の数式で頻出する形式として、 ${\bf b}^{\rm T}{\bf x}$ と ${\bf x}^{\rm T}{\bf A}{\bf x}$ の 2 つがある。
前者は**線形結合**もしくは**一次結合**、後者は**二次形式**と呼ばれている。
スカラの一次式 ($ax + b$) や二次式 ($ax^2 + bx + c$) をベクトルに拡張したものと捉えるとよいでしょう。

線形結合の計算を要素ごとに見てみると、

$$
\begin{aligned}
{\bf b}
&=
\begin{bmatrix}
1 \\
2
\end{bmatrix},\
{\bf x} =
\begin{bmatrix}
x_{1} \\
x_{2}
\end{bmatrix}\\
{\bf b}^{\rm T}{\bf x}
&=
\begin{bmatrix}
1 & 2
\end{bmatrix}
\begin{bmatrix}
x_1 \\
x_2
\end{bmatrix}
= x_1 + 2x_2
\end{aligned}
$$

のように ${\bf x}$ の要素である $x_1$ および $x_2$ に関して一次式となっている。

また、二次形式も同様に要素ごとに確認してみると、

$$
\begin{aligned}
{\bf A} &=
\begin{bmatrix}
1 & 2 \\
3 & 4
\end{bmatrix},\
{\bf x} =
\begin{bmatrix}
x_{1} \\
x_{2}
\end{bmatrix}\\
{\bf x}^{\rm T}{\bf A}{\bf x}
&=
\begin{bmatrix}
x_1 & x_2
\end{bmatrix}
\begin{bmatrix}
1 & 2 \\
3 & 4
\end{bmatrix}
\begin{bmatrix}
x_1 \\
x_2
\end{bmatrix} \\
&=
\begin{bmatrix}
x_1 & x_2
\end{bmatrix}
\begin{bmatrix}
x_1 + 2x_2 \\
3x_1 + 4x_2
\end{bmatrix} \\
&=
x_1 \left( x_1 + 2x_2 \right) + x_2 \left( 3x_1 + 4x_2 \right) \\
&=
x^2_1 + 5x_1 x_2 + 4x_2^2
\end{aligned}
$$

となり、各要素に関して二次式となっている。
一般に、$x_1, \ldots, x_N$ に関する二次関数は、

$$
{\bf x} = \begin{bmatrix}
x_1 \\
\vdots \\
x_n \\
\end{bmatrix}
$$

として、

$$
{\bf x}^{\rm T}{\bf A}{\bf x} + {\bf b}^{\rm T}{\bf x} + c
$$

と表記できる。ここで、 ${\bf A}$ は 2次の項の係数を表すサイズ $(n, n)$ の 行列、 ${\bf b}$ は1次の項の係数を表す $n$ 次元のベクトル、 $c$ はスカラの定数項である。

### ベクトルによる微分と勾配

微分は入力が変化した場合の関数値の変化量から求められました。
これは関数の入力がベクトルである場合も同様である。
ベクトルを入力にとる関数の微分を考えてみる。
入力ベクトルの要素毎に出力に対する偏微分を計算し、それらを並べてベクトルにしたものが**勾配 (gradient)** である。

まず勾配に関する計算の具体例を見てみる。

$$
\begin{aligned}
{\bf b}
&=\begin{bmatrix}
3 \\
4
\end{bmatrix}, \
{\bf x} =
\begin{bmatrix}
x_{1} \\
x_{2}
\end{bmatrix}\\
{\bf b}^{\rm T}{\bf x} &=
\begin{bmatrix}
3 & 4
\end{bmatrix}
\begin{bmatrix}
x_1 \\
x_2
\end{bmatrix}
= 3x_1 + 4x_2
\end{aligned}
$$

この ${\bf b}^{\rm T}{\bf x}$ をベクトル ${\bf x}$ で微分したものを、

$$
\frac{\partial}{\partial {\bf x}} \left( {\bf b}^{\rm T}{\bf x} \right)
$$

と表す。
「ベクトルで微分」とは、ベクトルのそれぞれの要素で対象を微分し、その結果を要素に対応する位置に並べてベクトルを作ることである。
前述の例では、以下のように計算を行う。

$$
\begin{aligned}
\frac{\partial}{\partial {\bf x}} \left( {\bf b}^{\rm T} {\bf x} \right)
&= \frac{\partial}{\partial {\bf x}} \left( 3x_1 + 4x_2 \right) \\
&=
\begin{bmatrix}
\frac{\partial}{\partial x_1} \left( 3x_1 + 4x_2 \right) & \frac{\partial}{\partial x_2} \left( 3x_1 + 4x_2 \right)
\end{bmatrix}
\end{aligned}
$$

各要素の計算を進めると、以下のようになる。本チュートリアルでは、ベクトルは原則として列ベクトルを用いるルールを採用しているが、ここでは微分した結果を行ベクトルで表していることに注意する。これは、後で登場するベクトル値関数（ベクトルを出力とする関数）の微分を考えた場合との整合性をとるためである。

$$
\begin{aligned}
\frac{\partial}{\partial x_1} \left( 3x_1 + 4x_2 \right)
&= \frac{\partial}{\partial x_1} \left( 3x_1 \right)
+ \frac{\partial}{\partial x_1} \left( 4x_2 \right) \\
&= 3 \times \frac{\partial}{\partial x_1} \left( x_1 \right)
+ 4x_{2} \times \frac{\partial}{\partial x_1} (1) \\
&= 3 \times 1 + 4x_{2} \times 0 \\
&= 3
\end{aligned}
$$

$$
\begin{aligned}
\frac{\partial}{\partial x_2} \left( 3x_1 + 4x_2 \right)
&= \frac{\partial}{\partial x_2} \left( 3x_1 \right)
+ \frac{\partial}{\partial x_2} \left( 4x_2 \right) \\
&= 3x_{1} \times \frac{\partial}{\partial x_2} (1)
+ 4 \times \frac{\partial}{\partial ax_2} (x_{2}) \\
&= 3x_{1} \times 0 + 4 \times 1 \\
&= 4
\end{aligned}
$$

従って、計算結果を整理すると、以下のようになる。

$$
\begin{aligned}
\frac{\partial}{\partial {\bf x}} \left( {\bf b}^{\rm T}{\bf x} \right)
&=
\begin{bmatrix}
\frac{\partial}{\partial x_1} \left( 3x_1 + 4x_2 \right) & \frac{\partial}{\partial x_2} \left( 3x_1 + 4x_2\right)
\end{bmatrix}
=
\begin{bmatrix}
3 & 4
\end{bmatrix}
=
{\bf b}^{\rm T}
\end{aligned}
$$

もう一つ別の例を考えてみる。今度は定数スカラーをベクトルで微分する。

$$
\begin{aligned}
c
&=
3 ,
{\bf x}
=
\begin{bmatrix}
x_{1} \\
x_{2}
\end{bmatrix} \\
\frac{\partial}{\partial {\bf x}} \left( c \right)
&=
\begin{bmatrix}
\frac{\partial}{\partial x_1} \left( 3 \right) & \frac{\partial}{\partial x_2} \left( 3 \right)
\end{bmatrix}
=
\begin{bmatrix}
0 & 0
\end{bmatrix}
=
{\bf 0}
\end{aligned}
$$

偏微分を行う対象に変数が含まれていない場合、その偏微分は $0$ となる。要素が $0$ のみで構成されたベクトルを**ゼロベクトル**と言い、数字の $0$ を太字にした ${\bf 0}$ で表す。

これらを踏まえて、機械学習で頻出する計算結果をまとめて覚えておく。

$$
\begin{aligned}
&\left( 1 \right) \ \frac{\partial}{\partial {\bf x}} \left( c \right) = {\bf 0} \\
&\left( 2 \right) \ \frac{\partial}{\partial {\bf x}} \left( {\bf b}^{\rm T}{\bf x} \right) = {\bf b}^{\rm T} \\
&\left( 3 \right) \ \frac{\partial}{\partial {\bf x}} \left( {\bf x}^{\rm T}{\bf A}{\bf x} \right) = {\bf x}^{\rm T} \left( {\bf A} + {\bf A}^{\rm T} \right)
\end{aligned}
$$

ここで、(1) と (2) はすでに導出済みである。(3) は導出が少し複雑なので省略するが、数値を代入して確認してみる。

## ベクトルを入力とする関数

前節で考えた ${\bf b^T x}$ や ${\bf x^T A x}$ は  ベクトル ${\bf x}$ を受け取って、スカラ ${\bf b^T x}$, ${\bf x^T A x}$ を出力する関数と考えることができる。 ${\bf x}$ を成分表示して

$$
{\bf x} = \begin{bmatrix} x_1 \\ x_2 \end{bmatrix}
$$

と書くと、この関数は 2 つのスカラ変数 $x_1$, $x_2$ を入力とする多変数関数である。
同様に、入力が $M$ 個のスカラ変数の関数は、 $M$ 次元のベクトル 1 個を入力とする関数とも解釈することができる。
多変数関数 $f(x_1, \ldots, x_M)$ は、入力をまとめて

$$
{\bf x} = \begin{bmatrix} x_1 \\ \vdots \\ x_M \end{bmatrix}
$$

と書き、 $f({\bf x})$ と表記しても構わない。 $f({\bf x})$ の微分は、前章で説明した偏微分を各変数 $x_1, \ldots, x_M$ に対して行い

$$
\frac{\partial}{\partial {\bf x}} f({\bf x}) =
\begin{bmatrix}
    \frac{\partial}{\partial x_1} f({\bf x})  & \dots & \frac{\partial}{\partial x_M} f({\bf x}) \\
\end{bmatrix}
$$

と計算する。

## ベクトル値関数

次に入力ではなく出力が多変数の関数を考えます。
まず、1 つのスカラ変数 $x$ を入力とし、 $N$ 個のスカラ（つまり、 $N$ 次元のベクトルを 1 個）を出力する関数 ${\bf f}(x)$ を考えます。
ベクトル変数は ${\bf y}$ などの太字で書いていました。それと同様に、この関数も出力がベクトルであることを強調して ${\bf f}$ と太字で表す。
${\bf f}$ のように出力がベクトルである関数を **ベクトル値関数 (vector-valued function)** と呼ぶ。それに対し、出力がスカラである関数を（そのことを強調したい場合には） **スカラ値関数 (scalar-valued function)** と呼ぶ。

${\bf f}$ の出力の各成分に注目すると、 ${\bf f}$ は $N$ 個のスカラ値関数の集まりと考えることができる。
つまり、 $x$ を受け取り、 ${\bf f}$ の 第 $n$ 成分を出力する関数を $f_n$ と書くと、

$$
{\bf f}(x) = \begin{bmatrix}f_1(x) \\ \vdots \\ f_N(x)\end{bmatrix}
$$

である。
入力が多変数でも同様に成分表示することができる。すなわち、入力変数が $M$ 次元ベクトル、出力変数が $N$ 次元ベクトルである関数 ${\bf g}$ は

$$
{\bf g}({\bf x}) =
\begin{bmatrix}g_1({\bf x}) \\ \vdots \\ g_N({\bf x})\end{bmatrix} =
\begin{bmatrix}g_1(x_1, \ldots, x_M) \\ \vdots \\ g_N(x_1, \ldots, x_M)\end{bmatrix}
$$

と成分表示できる。誤解が生じないならば、一番右の表式のように入力変数 ${\bf x}$ を成分表示しても構わない。

## ベクトル値関数の微分

ベクトル値関数の微分を行うには、各成分ごとにスカラ値関数と同様の方法で微分する。例えば前節の ${\bf f}$ の微分は

$$
{\bf f}'(x) = \begin{bmatrix} f'_1(x) \\ \vdots \\ f'_N(x) \end{bmatrix}
$$

である。出力がベクトルであることに対応して、微分もベクトルであることに注意する。
微小量を表す $d$ を用いて

$$
\frac{d}{dx} {\bf f} (x) = \begin{bmatrix} \frac{d}{dx}f_1(x) \\ \vdots \\ \frac{d}{dx}f_N(x) \end{bmatrix}
$$

と書いても構わない。

入出力が共に多変数である関数を微分する場合も、出力の成分ごとに微分する。
ただし、今度は入力も多変数であるため、入力の成分ごとに偏微分を行わなければならない。
例えば、前節の ${\bf g}$ を微分すると、前節の成分表示を用いて

$$
\frac{\partial {\bf g}}{\partial {\bf x}}({\bf x}) =
\begin{bmatrix}
    \frac{\partial g_{1}}{\partial {x_1}}({\bf x}) & \cdots & \frac{\partial g_{1}}{\partial {x_M}}({\bf x}) \\
    \vdots & \ddots & \vdots \\
    \frac{\partial g_{N}}{\partial {x_1}}({\bf x}) & \cdots & \frac{\partial g_{N}}{\partial {x_M}}({\bf x})
\end{bmatrix}
$$

となる。 $M$ 個の入力変数と $N$ 個の出力変数の組み合わせを考える必要があるので、微分はサイズ $(N, M)$ の行列となることに注意する。この、すべての偏微分の組み合わせをまとめて作った行列のことを **ヤコビ行列** と呼ぶ。

## 合成関数の微分（多変数バージョン）

先程 1 変数入力、1 変数出力の合成関数の微分（連鎖律）を説明しました。
類似の定理が多変数入力、多変数出力の場合にも成立する。
本節では多変数バージョンの合成関数の微分の公式を紹介する。

${\bf g}$ を $M$ 変数入力 $N$ 変数出力、${\bf f}$ を $N$ 変数入力 $L$ 変数出力の関数とする。
これらの関数の合成 ${\bf h} = {\bf f}({\bf g} ({\bf x}))$ は $M$ 変数入力 $L$ 変数出力の関数であることに注意する。
これを $x$ で微分する。
以下の式が多変数関数バージョンの合成関数の微分の公式である。

$$
\frac{\partial {\bf h}}{\partial {\bf x}}({\bf x})  = \frac{\partial {\bf f}}{\partial {\bf u}}({\bf u}) \frac{\partial {\bf g}}{\partial {\bf x}}({\bf x}).
$$

ここで、 ${\bf u} = {\bf g}({\bf x})$である。

1 変数入力、1変数出力の場合の合成関数の微分の公式と見比べると細字だった変数や関数が太字となり $d$ であった所が偏微分を表す $\partial$ に置き換えられている。すなわち、 1 変数の場合との最も大きな違いは

$$
\frac{\partial {\bf h}}{\partial {\bf x}}({\bf x}),
\frac{\partial {\bf f}}{\partial {\bf u}}({\bf u}),
\frac{\partial {\bf g}}{\partial {\bf x}}({\bf x})
$$

が行列であることである。行列のサイズはそれぞれ $(L, M)$, $(L, N)$, $(N, M)$ である。
それに伴い、公式の右辺の掛け算は行列積である。サイズが $(L, N)$ と $(N, M)$ なので、行列積がきちんと定義できることに注意する。
また、行列の積は交換可能ではないので、右辺を交換して $\frac{\partial {\bf g}}{\partial {\bf x}}({\bf x}) \frac{\partial {\bf f}}{\partial {\bf u}}({\bf u})$ とすると別の意味になってしまう（そもそも定義することができないかもしれない）ことにも注意する。

$M = N = L = 1$ とすると、前節の合成関数の微分と全く同じ公式である。
その意味で多変数関数の合成関数の微分は 1 変数の場合を一般化した公式である。
逆に、1 変数の公式は多変数の公式の特別な場合と言うこともできる。

### 計算例1

合成関数の微分を使って、多変数関数の微分を具体的に計算してみる。

$$
{\bf x} = \begin{bmatrix} x_1 \\ x_2 \end{bmatrix},
{\bf u} = \begin{bmatrix} u_1 \\ u_2 \\ u_3 \\ u_4 \end{bmatrix}
$$

として、

$$
{\bf g}({\bf x}) =
\begin{bmatrix}
    3x_1 + 1 \\
    2x_2 + 4 \\
    x_1 x_2 \\
    5
\end{bmatrix},
{\bf f}({\bf u}) =
\begin{bmatrix}
    2 u_1 + 1 \\
    u_2^2 + u_3^2 \\
    u_3 u_4
\end{bmatrix}
$$

とする。
つまり、${\bf g}$ は 2 入力 4 出力、${\bf f}$ は 4 入力 3 出力である。

これらについて $\frac{\partial {\bf f}({\bf g}({\bf x}))}{\partial {\bf x}}$ を計算する。
偏微分を定義どおり計算すると

$$
\begin{align*}
\frac{\partial {\bf g}}{\partial {\bf x}} ({\bf x})&=
\begin{bmatrix}
    \frac{\partial g_1}{\partial x_1} & \frac{\partial g_1}{\partial x_2} \\
    \frac{\partial g_2}{\partial x_1} & \frac{\partial g_2}{\partial x_2} \\
    \frac{\partial g_3}{\partial x_1} & \frac{\partial g_3}{\partial x_2} \\
    \frac{\partial g_4}{\partial x_1} & \frac{\partial g_4}{\partial x_2}
\end{bmatrix} =
\begin{bmatrix}
    3 & 0 \\
    0 & 2 \\
    x_2 & x_1 \\
    0 & 0
\end{bmatrix}\\
\frac{\partial {\bf f}}{\partial {\bf u}} ({\bf u})&=
\begin{bmatrix}
    \frac{\partial f_1}{\partial u_1} & \frac{\partial f_1}{\partial u_2} & \frac{\partial f_1}{\partial u_3} & \frac{\partial f_1}{\partial u_4}\\
    \frac{\partial f_2}{\partial u_1} & \frac{\partial f_2}{\partial u_2} & \frac{\partial f_2}{\partial u_3} & \frac{\partial f_2}{\partial u_4}\\
    \frac{\partial f_3}{\partial u_1} & \frac{\partial f_3}{\partial u_2} & \frac{\partial f_3}{\partial u_3} & \frac{\partial f_3}{\partial u_4}\\
\end{bmatrix} =
\begin{bmatrix}
    2 & 0 & 0 & 0\\
    0 & 2u_2 & 2u_3 & 0 \\
    0 & 0 & u_4 & u_3
\end{bmatrix}
\end{align*}
$$

となる（行列中の $\frac{\partial g_1}{\partial x_1}$ などは本来は $\frac{\partial g_1}{\partial x_1}({\bf x})$ などと書くべきであるが、式が煩雑になるため省略しました）。
よって、合成関数の微分の公式より、

$$
\begin{align*}
\frac{\partial {\bf f}({\bf g}({\bf x}))}{\partial {\bf x}}
&=
\begin{bmatrix}
    2 & 0 & 0 & 0\\
    0 & 2u_2 & 2u_3 & 0 \\
    0 & 0 & u_4 & u_3
\end{bmatrix}
\begin{bmatrix}
    3 & 0 \\
    0 & 2 \\
    x_2 & x_1 \\
    0 & 0
\end{bmatrix} \\
&=
\begin{bmatrix}
    6 & 0 \\
    2u_3x_2 & 4u_2 + 2u_3x_1 \\
    u_4x_2 & u_4x_1
\end{bmatrix} \\
&=
\begin{bmatrix}
    6 & 0 \\
    2x_1x_2^2 & 2x_1^2x_2 + 8x_2 + 16 \\
    5x_2 & 5x_1
\end{bmatrix}
\end{align*}
$$

となる。公式を適用する際に ${\bf u} = {\bf g}(\bf x)$ 、すなわち

$$
\begin{bmatrix}
    u_1 \\
    u_2 \\
    u_3 \\
    u_4
\end{bmatrix} =
\begin{bmatrix}
    3x_1 + 1 \\
    2x_2 + 4 \\
    x_1 x_2 \\
    5
\end{bmatrix}
$$

を用いました。

### 計算例2

もう1つの例として、合成した関数の入出力が 1 変数となる場合、つまり、$M = 1, L = 1$ の場合を考えてみる。
式を簡単にするために、 $N = 2$ とする。
1 変数であることを強調して、 ${\bf u} = {\bf g}(x)$, $y = f({\bf u})$ とスカラーとなる変数には小文字を用いることにする。
$f$ と ${\bf g}$ を合成した関数を $h(x) = f({\bf g}(x))$ とする。
$h$ は 入出力が共に 1 変数なので、その微分を簡便に $h'(x)$ と書くことにすると、合成関数の微分の公式は

$$
\begin{align*}
h'(x) &=
\frac{\partial f}{\partial {\bf u}} ({\bf u}) \frac{d {\bf g}}{d x} (x)\\
&= \begin{bmatrix}
    \frac{\partial f}{\partial u_1} ({\bf u}) & \frac{\partial f}{\partial u_2} ({\bf u})
\end{bmatrix}
\begin{bmatrix}
    \frac{d g_1}{d x} (x) \\
    \frac{d g_2}{d x} (x)
\end{bmatrix} \\
&=
\frac{\partial f}{\partial u_1} ({\bf u})\frac{d g_1}{d x}(x) +
\frac{\partial f}{\partial u_2} ({\bf u})\frac{d g_2}{d x}(x)
\end{align*}
$$

と書き下すことができる（微分する変数が 1 つしかない場合は偏微分記号 $\partial$ ではなく 1 変数微分 $d$ を用いて書きました）。

本資料で紹介した合成関数の微分の公式の他にも行列やベクトルの計算で用いられる公式はたくさんある。
それらの公式は [The Matrix Cookbook](https://www.math.uwaterloo.ca/~hwolkowi/matrixcookbook.pdf) などにまとまっているので、論文等を読む際などにも必要に応じてこれらを参照するとよいでしょう。
また、ヤコビ行列の計算方法は [The Matrix Calculus You Need For Deep Learning](https://arxiv.org/abs/1802.01528)などにまとまっている。

**注釈 1**

$N \times M$ 行列、などと言われたときに、$N$ と $M$ のどちらが行で、どちらが列だろう？と迷ったときは、「行列」と言う言葉を再度思い浮かべて、「行→列」つまり先にくる $N$ が行数で、$M$ が列数だ、と思い出すのがおすすめである。

[▲上へ戻る](#ref_note1)

**注釈 2**

文献によっては単位行列ではなく、すべての成分が1の行列のことをunit matrixと呼ぶこともある。

[▲上へ戻る](#ref_note2)

# 確率・統計の基礎

本節では機械学習で用いる確率論、統計学の概念や用語を解説する。

世の中には「ランダム」に起こる出来事、もしくは背景のメカニズムがわからないため「ランダム」として扱わざるを得ない出来事が存在する。そのようなランダムな出来事を理論的に扱うには、出来事そのものや、ある出来事と別の出来事の関連を数学的に記述できなければならない。確率論ではランダムな出来事のことを**事象 (event)**と呼ぶ（厳密な定義は本資料では省略する）。

本節では、まず事象を記述する道具として確率分布を導入し、それに関連する概念（周辺確率、条件付き確率、確率変数の独立）を解説する。さらにこれらの概念を用いてベイズの定理を説明する。ベイズの定理により、ある出来事が観測された時に、その原因となる出来事が起こった確率の計算ができるようになる。
次に、確率分布の中から観測データに適合した最適な確率分布を選択する方法である、最尤推定と事後分布最大化推定（MAP 推定）を紹介する。
機械学習の文脈では、これらは訓練モデルの「最適な」パラメータを決定することに対応する。
最後に、機械学習で頻繁に利用される統計学の用語（平均、分散、標準偏差、相関係数など）を解説する。

## 確率・統計と機械学習の関係

機械学習システムが学習に用いるのは限られた数の観測データであるが、多くの機械学習タスクでやりたいことは、与えられた観測データの背後にある普遍性や法則を捉え、将来の出来事に対し予測を行えることである。機械学習ではそれを達成するために統計学の考え方を利用する。

統計学では、ある集団すべてについて調査ができない時、集団からランダムサンプリングを行い元の集団の性質を推定する。手元にある観測データが、何らかの法則に従って得られる確率的なサンプルであると考えることで、機械学習と統計学がつながる。
統計学を利用することで、あるデータが未知のデータ源から発生しやすいか、データが外れ値かどうか、どういった方法でモデルを学習させればよいか、といった問題を客観的に判断することができるようになる。また、学習させたモデルの性能に対して理論的な保証を与えることも統計学により可能となる。
このような、機械学習の統計学としての側面を強調する場合、機械学習を特に「統計的機械学習」と呼ぶ。

## 確率変数と確率分布

現代数学で広く利用されている「確率」の概念を定式化するには様々な準備が必要になるため、この資料では「確率」と言う言葉を数学的に厳密には定義しない。代わりに次のように考えます。ある対象としている現象の中で、様々な事象があり得るとき、それぞれの事象ごとに、それが「どの程度起きそうか」と言う度合いを考えます。確率とはその度合いのこととする。そして、その確率に従って、色々な値をとりうる**確率変数（random variable）**を考えます。確率変数は、名前に「変数」とついているが、**「事象」を「数値」に変換する関数**と考えると理解しやすくなる。例えば、「コインを投げて表が出る」と言う「事象」を、「1」と言う「数値」に変換し、「コインを投げて裏が出る」と言う「事象」を、「0」と言う「数値」に変換する関数を考えると、これは「1」か「0」と言う値のどちらかをとりうる確率変数だ（[注釈1](#note1)）と言うことになる。

それでは、確率的現象の具体例を考えてみる。ある歪んだサイコロがあり、「サイコロを投げて $x$ と言う目が出た」と言う事象（[注釈2](#note2)）を、$x$ と言う数値に対応させる確率変数 $X$ があるとする。そして、この確率変数がとりうる全ての値が、それぞれどのような確率で出現するかを表した以下のような表がある。

| 確率変数 $X$ の値 | その値をとる確率 |
|:-----------------:|:----------------:|
| 1                 | $0.3$            |
| 2                 | $0.1$            |
| 3                 | $0.1$            |
| 4                 | $0.2$            |
| 5                 | $0.1$            |
| 6                 | $0.2$            |

このような表を**確率分布 (probability distribution)** と呼ぶ。確率分布には重要な制約があり、「確率変数がとりうるあらゆる値の確率をすべて足すと和が必ず $1$ になること」及び「全ての確率は $0$ 以上の値であること」の両者を常に満たす。上の表の左の列に並ぶ数値を**実現値**と呼び、小文字の $x$ で表す。そして、右の列に並ぶそれぞれの $x$ に対応する確率を $p(x)$ と書くことにする。すなわち上の表から $p(1) = 0.3$ , $p(2) = 0.1$ , $\ldots$ である。この表記を用いると、確率分布が持つ2つの制約は、以下のように表せます。

$$
\begin{align}
\sum_x p(x) &= 1 \\
\forall x, \ p(x) & \geq  0
\end{align}
$$

ここで、 $\sum_x$ は全てのありうる $x$ の値にわたる和を表し、例えば上のサイコロの例では、 $\sum_{x=1}^6$ と同じことを意味する。 $\forall x$ は、あり得る $x$ の値すべてにおいて、右の条件（ $p(x) \geq 0$ ）が成り立つ、と言うことを意味している。

$p(1) = 0.3$ と言うのは、確率変数 $X$ が $1$ と言う値をとる確率と言うことであるが、これを $p(X = 1) = 0.3$ とも書く。前述の $p(x)$ は、確率変数 $X$ の存在を暗に仮定し、 $p(X = x)$ を簡単に表記したもの、すなわち $X$ と言う確率変数がある値 $x$ をとる確率と考えることができる。一方、 $p(X)$ と確率変数だけを引数にとる場合、これは上の表のような確率分布を意味する。

## 同時分布・周辺確率

前節では、1 つの確率変数について、その分布（確率分布のこと）とは何かと、分布が持つ制約について説明しました。この節では、複数の確率変数が登場する場合について考えます。

まず具体例を用いて考えてみる。ここに 2 つのサイコロがあり、それぞれのサイコロの出目を 2 つの確率変数 $X, Y$ で表す。この 2 つのサイコロを同時に振って、1 つ目のサイコロが $x$ と言う値をとり、2 つ目のサイコロが $y$ と言う値をとったと言う事象の確率は、以下のように書き表す。

$$
p(X = x, Y = y)
$$

 $x, y$ はいずれも $1, 2, 3, 4, 5, 6$ の6つの数字のどれかである。例えば、「3」と「5」の目が出る、と言う事象が起こる確率は

$$
p(X = 3, Y = 5)
$$

と表されます。このように、 $X = 3$ となる**かつ** $Y = 5$ となる、といった複数の条件を指定したときに、それらが全て同時に成り立つ確率のことを、**同時確率（joint probability）**と呼ぶ。

では次に、この 2 つのサイコロを別々に見てみる。例えば、「1 つ目のサイコロが $3$ の目を出した」と言う事象が起こる確率 $p(X = 3)$ は、1つ目のサイコロが $3$ **かつ** 2 つ目のサイコロが $1$ のとき／ $2$ のとき／ $3$ のとき／…／ $6$ のとき、の6つのパターンが発生する確率を全て足したものになる。つまり、

$$
p(X = 3) = \sum_y p(X = 3, Y = y)
$$

と書けます。このとき、 $\sum_y$ は「 $Y$ のとり得るあらゆる値 $y$ についての和」と言う意味である。これを、「（2 つ目のサイコロの目がなんであれ） 1 つ目のサイコロの目が $x$ である確率」と一般化すると、以下のようになる。

$$
p(X = x) = \sum_y p(X = x, Y = y)
$$

同様に、「（1つ目のサイコロの目がなんであれ）2 つ目のサイコロの目が $y$ である確率」は、1つ目のサイコロについてあり得る値すべての確率の和を取ればよいので、

$$
p(Y = y) = \sum_x p(X = x, Y = y)
$$

となる。このように、同時確率が与えられたとき、着目していない方の確率変数がとり得る全ての値について同時確率を計算しその和をとることを**周辺化 (marginalization)** と呼び、結果として得られる確率を**周辺確率 (marginal probability)** と呼ぶ。
また、周辺確率をその着目している確率変数がとり得る全ての値について並べて一覧にしたものが**周辺確率分布 (marginal probability distribution)** である。
さらに、上の例のように2つの確率変数の同時確率を考えるとき、とり得る全ての組み合わせの確率を一覧にしたものが、**同時分布 (joint distribution)** である。

ここで、2 つのサイコロの同時分布の表は大きくなってしまうので、より簡単な例として、表が出る確率と裏が出る確率が異なる 2 つのコインを考えてみる。この 2 つのコインを同時に投げたときの表裏の組み合わせについての同時分布が、以下のようになったとする。

| $\ $   | Y = 表 | Y = 裏 |
|:------:|:------:|:------:|
| X = 表 | 1 / 5  | 2 / 5  |
| X = 裏 | 1 / 5  | 1 / 5  |

ここで、1 つ目のコインの表裏を表す確率変数を $X$ 、2 つ目のコインの表裏を表す確率変数を $Y$ としている。表の中身がどう言う意味を持っているか確認する。2 つのコインが両方表になる確率は $p(X = 表, Y = 表) = 1 / 5$ となっている。他のマスに書かれている同時確率の値の意味も確認する。

では、この表の中の数字を、行ごとに合計してみる。1 行目は、

$$
p(X = 表, Y = 表) + p(X = 表, Y = 裏) = 1 / 5 + 2 / 5 = 3 / 5
$$

である。
これは、 $\sum_y p(X = 表, Y = y)$ （[注釈3](#note3)）を計算していることになるので、**周辺化によって** $p(X = 表)$ **と言う周辺確率を求めていることに相当する。**

同様に、1 列目の値を合計してみると、今度は $\sum_x p(X = x, Y = 表)$ （[注釈4](#note4)） を計算することに相当し、これは周辺化によって $P(Y = 表)$ と言う周辺確率を計算していることになる。

こうして計算される周辺確率を、上の同時分布の表に書き入れてみる。

| $\ $   | Y = 表 | Y = 裏 | p(X)  |
|:------:|:------:|:------:|:-----:|
| X = 表 | 1 / 5  | 2 / 5  | 3 / 5 |
| X = 裏 | 1 / 5  | 1 / 5  | 2 / 5 |
| p(Y)   | 2 / 5  | 3 / 5  |       |

このように、周辺確率はしばしば同時分布表の周辺に記述されます。

## 条件付き確率

前節では、複数の確率変数を同時に考える方法として、同時確率および同時分布と言う概念と、同時確率と一つ一つの確率変数のみに着目した際の確率（周辺確率）の間の関係を、周辺化と言う計算で説明しました。
本節では、「とある条件下での着目事象の確率」を考える**条件付き確率 (conditional probability)** と言う概念を説明する。
これまでの節で扱っていた確率では、まず対象とする現象について、考えうる全ての事象を考え、そのうち対象とする事象が起きる確率はいくらか、を考えていました。
一方、条件付き確率は、それらの考えうる事象のうち、特定の条件を満たした事象のみをまず抜き出し、その中で、さらに着目する特定の事象が起きる確率を考えるためのものである。

例えば、あるお店にやってきた人（以下、客）が傘を持っているときに $1$ 、持っていなかったときに $0$ をとる確率変数 $X$ を考えます。
また、ある客がやってきたときに外で雨が降っていたときに $1$ 、降っていなかったときに $0$ をとる確率変数 $Y$ を考えます。
客が傘を持っていたかと、その瞬間に雨が降っていたかどうか、と言う 2 つの情報が組となったデータが 16 個あるとする。
16 人の客を観測してデータを集めた、と言うことである。
それは以下の様なものでした。

| 傘 ( $X$ ) | 雨 ( $Y$ ) |
|:--------:|:-------:|
| 1 | 1 |
| 1 | 1 |
| 1 | 1 |
| 1 | 1 |
| 1 | 1 |
| 1 | 1 |
| 0 | 1 |
| 0 | 1 |
| 0 | 1 |
| 1 | 0 |
| 0 | 0 |
| 0 | 0 |
| 0 | 0 |
| 0 | 0 |
| 0 | 0 |
| 0 | 0 |

これらのデータから、確率変数 $X, Y$ の同時分布表を作成すると、以下のようになる。この表の作り方は、例えば表の左上のマスは $X = 0$ かつ $Y = 0$ となっているデータが　16 個中何個あるかを数えて、その割合を記入すればよく、他のマスについても同様となる。

| $\ $  | Y = 0  | Y = 1  |
|:-----:|:------:|:------:|
| X = 0 | 6 / 16 | 3 / 16 |
| X = 1 | 1 / 16 | 6 / 16 |

では、「客が傘を持っていた（ $X = 1$ ）」と言う**条件の下で**、「そのとき雨が降っていなかった（ $Y = 0$ ）」と言う確率は、どのようになるでしょうか？

まず、「客が傘を持っていた（ $X = 1$ ）」と言う状況下のデータだけを、上の同時分布表から抜き出しておく。

| 傘 ($X$) | 雨 ($Y$) |
|:--------:|:-------:|
| 1 | 1 |
| 1 | 1 |
| 1 | 1 |
| 1 | 1 |
| 1 | 1 |
| 1 | 1 |
| 1 | 0 |

全部で 7 個のデータがあり、この中で「雨が降っていなかった（ $Y = 0$ ）」となっているデータは 1 個である。すなわち、「客が傘を持っていたと言う**条件の下で**、そのとき雨が降っていなかった確率」は $1 / 7$ となる。これを、以下のように書く。

$$
p(Y = 0 | X = 1) = \frac{1}{7}
$$

これが**条件付き確率**と呼ばれるもので、条件となる事象を縦棒 $|$ の後に書き、その条件下で注目している事象を縦棒 $|$ の前に書く。同様に、「客が傘を持っていたと言う**条件の下で**、そのとき雨が降っていた確率」は、上の表から $6 / 7$ なので、以下が成り立ちます。

$$
p(Y = 1 | X = 1) = \frac{6}{7}
$$

これらの 2 つの確率が、それぞれ $p(Y = 0, X = 1) = 1 / 16$ , $p(Y = 1, X = 1) = 6 / 16$ と言う同時確率とは異なっていることを、上の同時分布表と見比べて確認してみる。
「客が傘を持っていて**かつ**外で雨が降っている」と言う同時確率は $6 / 16$ となっているが、「客が傘を持っていると言う**条件の下で**外で雨が降っている」と言う条件付き確率は $6 / 7$ でした。
前者は「客が傘を持っておらず外で雨が降っていた」「客が傘を持っておらず外で雨が降っていなかった」「客が傘を持っていたが外で雨が降っていなかった」を含むあり得る全ての事象を考えた上で、その中で対象としている事象「客が傘を持っていて外で雨が降っている」が起こる確率を意味している。一方で、後者の条件付き確率は、今条件となっている事象「客が傘を持っている」が成り立っている事象だけをまず対象とし、その中で着目している事象「外で雨が降っている」が起こる確率を考えます。それぞれの確率の値を計算する際の分母が異なっていることに注目する。

また、上記の 2 つの条件付き確率を足すと、 $1$ になる。「ある条件下で」と言う制約された世界で、対象とする確率変数がとり得る値全ての確率を並べて一覧したものは**条件付き分布（conditional distribution）**と呼ばれ、それらの確率を全て足すと必ず $1$ になる。上の例では、以下の計算で確かめられます。

$$
p(Y = 0 | X = 1) + p(Y = 1 | X = 1) = \frac{1}{7} + \frac{6}{7} = 1
$$

ここで、確率変数 $X$ がとりうる実際の値のうちいずれかを表す文字として $x$ を、確率変数 $Y$ がとりうる実際の値のうちいずれかを表す文字として $y$ を用いると、一般的に、条件付き確率は以下のように定義されます。

$$
p(Y = y | X = x)
= \frac{p(X = x, Y = y)}{p(X = x)}
$$

このとき、条件付き分布が満たす条件は以下のように表せます。

$$
\sum_y p(Y = y | X = x) = 1
$$

ここで、 $\sum_x P(Y = y | X = x)$ は必ずしも1にならないと言うことに注意する。

では、上の条件付き確率の定義を用いて、同時確率と周辺確率から条件付き確率を、再度計算してみる。

$$
\begin{align}
p(Y = 0 | X = 1)
&= \frac{p(X = 1, Y = 0)}{p(X = 1)} \\
&= \frac{\frac{1}{16}}{\frac{7}{16}} \\
&= \frac{1}{7}
\end{align}
$$

確かに、上で別の方法で求めた条件付き確率と一致しました。

さて、上で触れた、同時確率と条件付き確率の関係について再度考えてみる。前述の「条件付き確率の定義」の式を変形すると、以下のようになる。以降では、簡単のために、確率変数の記述を省き、 $p(X = x)$ を $p(x)$ と表記する。確率変数 $X$ によって $x$ と言う値に対応付けられている事象が生じる確率、と言う意味である。同様に、 $p(Y = y)$ を $p(y)$ と表記する。

$$
p(x, y) = p(y | x) p(x)
$$

同時確率は、条件付き確率に、その条件となっている事象が生じる確率（周辺確率）を掛け合わせることで得られることが分かる。

今回の例では、「雨が降っているかどうか」によって「客が傘を持っていたかどうか」は影響を受けるため、2つの確率変数 $Y, X$ は**従属 (dependent)**、と言う。一方、例えば「客が来たとき雨が降っていたかどうか」と「私が今お腹が空いているかどうか」が全く関係していないとする。後者について、お腹が空いていると言う事象を $1$ に、お腹が空いていないと言う事象を $0$ に対応付ける確率変数 $Z$ を導入すると、$Y$ と $Z$ が今**独立 (independent)**であると言う状況である。このとき、$Z$ の実現値を $z$ として、条件付き確率 $p(y | z)$ は、$Y$ がどうなるかが $Z$ がどうなるかに全く関係がないことから、 $p(y)$ と等しくなる。条件付けたとしても、条件付けなかったとしても、結果が変わらないためである。これを用いると、 $y$ と $z$ の同時確率は以下のように変形できる。

$$
\begin{align}
p(y, z) &= p(y | z) p(z) \\
p(y, z) &= p(y) p(z)
\end{align}
$$

 $Y$ と $Z$ が独立であることから、 $p(y | z) = p(y)$ となることを用いました。この式から、**2つの確率変数が独立であるとき、同時確率はそれぞれの周辺確率の積で書ける**と言うことが言えます。

## ベイズの定理

前節で説明した条件付き確率は、ある前提が成り立っている状況下で着目する事象が生じる確率を記述するためのものでした。これは、「ある"原因"が生じたと言う条件の下で、ある"結果"が生じる確率」を考えていると捉えることができる。では、逆に**「ある"結果"が観測されたと言うとき、ある事象が"原因"である確率」**を考えるにはどうしたらよいでしょうか。今、原因となり得る事象が確率変数 $X$ で表され、結果となり得る事象が確率変数 $Y$ で表されるとする。このとき、原因として実際に $x$ が観測されたもとで結果が $y$ となる確率が条件付き確率

$$
p(Y = y | X = x)
$$

で表されました。前節の定義から、これに原因 $x$ がそもそも発生する確率 $p(X = x)$ を掛け合わせると、同時確率 $p(Y = y, X = x)$ になる。すなわち、

$$
p(Y = y | X = x) p(X = x) = p(Y = y, X = x) \hspace{2em} \cdots (1)
$$

である。では、結果が $y$ であったと言う観測の下で、原因が $x$ である確率はどのように表されるでしょうか。これは上の「条件の事象」と「着目する事象」を入れ替えた条件付き確率として、

$$
p(X = x | Y = y)
$$

と書くことができる。 $y$ と言う結果が観測されたもとで、原因が $x$ であった確率と言う意味である。これに結果 $y$ がそもそも発生する確率 $p(Y = y)$ をかけ合わせると、条件付き確率の定義から

$$
p(X = x| Y = y) p(Y = y) = p(X = x, Y = y) \hspace{2em} \cdots (2)
$$

が導かれます。ここで、式(1)と式(2)の右辺が同じになっていることに着目する。すると、式(1)と式(2)の左辺同士を等号で結ぶことができ、

$$
p(Y = y | X = x) p(X = x) = p(X = x | Y = y) p(Y = y)
$$

が成り立つことが分かる。この式を変形して、求めたい「結果 $y$ が生じたと言う**条件の下で**原因が $x$ である確率」を左辺に残すと、

$$
p(X = x | Y = y) = \frac{p(Y = y | X = x) p(X = x)}{p(Y = y)}
$$

が導かれます。これを**ベイズの定理（Bayes' theorem）**と言う。これによって、ある結果が観測されたときに、ある事象が原因である確率を、

- 原因として考えている事象が（結果と関係なく）そもそも生じる確率（ $p(X = x)$ ）
- 結果として観測した事象が（原因に関係なく）そもそも生じる確率（ $p(Y = y)$ ）
- 考えている原因が実際に生じたと言う下で観測された結果が生じる確率（ $p(Y = y | X = x)$ ）

の3つから、求めることができる。ベイズの定理に登場する左辺の条件付き確率と右辺の分子にある周辺確率には、特別な呼び方がある。まず右辺の分子にある周辺確率（上式では $p(X = x)$ ）は、「結果」が観測する前（事前）に、原因 $x$ がそもそも生じる確率を表すので、**事前確率（prior probability)**と呼ばれます。一方、左辺の条件付き確率（上式では $p(X = x | Y = y)$ ）は、ある「結果 $y$」が観測されたと言う条件の下で（事後に）、原因 $x$ が生じていたと言う確率を表すので、**事後確率（posterior probability）**と呼ばれます。

ベイズの定理の応用事例として、スパムメールフィルターがある。まず、 $N$ 個の着目する単語 $w_i (i=1, \dots, N)$ を決めます（"sale", "buy", "free", ...など）。そして、メールにある単語 $w_i$ が含まれるとき $1$ となり、含まれないとき $0$ となる確率変数を $W_i$ とし、「メールにある単語 $w_i$ が含まれる確率」を $p(W_i = 1)$ とする。 次に、メールがスパムメールであるとき $1$ となり、スパムメールでないとき $0$ となる確率変数を $Y$ とし、「スパムメールの存在確率」を $p(Y = 1)$ とする。このとき、「あるメールがスパムメールであったと言う**状況の下で**単語 $w_i$ が含まれていた」と言う確率は $p(W_i = 1 | Y = 1)$ となる。すると、例えば $w_i$ と $w_j$ が両方含まれていた場合は、同時確率 $p(W_i = 1, W_j = 1 | Y = 1)$ を考えることになるが、各単語が独立に現れると仮定すると、これは $p(W_i = 1 | Y = 1) p(W_j = 1 | Y = 1)$ と分解できる。ここで、世の中にある大量のメールを集めて、各単語がどのくらいの確率で現れるかを調べると、 $p(W_i = 1) \ (i=1,\dots,N)$ が求まる。また、集めたメールからスパムメールだけを抜き出す。すると、メールがスパムメールである確率 $p(Y = 1)$ が求まる。さらに、それらのスパムメール中に含まれる単語を調べ、どの単語がどう言う確率で出現しているかを、着目している全単語について求めると、 $p(W_i = 1 | Y = 1) \ (i=1, \dots, N)$ が全て求まる。これらを用いると、「あるメールに単語 $w_i, w_j, w_k, \dots$ らが含まれているとき、そのメールがスパムメールである確率」を以下のように計算できる。

$$
p(Y = 1 | W_i = 1, W_j = 1, W_k = 1, \dots ) = \frac{p(W_i = 1, W_j = 1, W_k = 1, \dots | Y = 1) p(Y = 1)}{p(W_i = 1, W_j = 1, W_k = 1, \dots )}
$$

## 尤度と最尤推定

これまでの節では、「**確率変数がとりうる様々な値に確率を対応させる**」確率分布は、表の形で表されていました。ここで、確率変数 $X$ が $x$ と言う値をとる確率 $p(X = x)$ を、表の代わりに、あるパラメータ $\theta$ で特徴づけられた関数 $f(x; \theta)$ によって表してみる。この関数は、「**確率変数** $X$ **がとりうる様々な値** $x$ **に確率を対応させる**」ので、 $X$ の確率分布を表している。このような関数は**確率モデル（probabilistic model）**とも呼ばれ、特にパラメータによって形状が決定される関数を用いる場合は**パラメトリックモデル（parametric model）**と呼ばれます。

このような確率モデルのパラメータをうまく決定することで、データの分布を表現できれば、未知のデータに対してもそれがどのくらいの確率で発生するのかといった予測が可能となったり、便利である。推定方法には様々なものがあり、どうやって推定するかは推定する人の自由であるが、本節では最も一般的な方法の一つである最尤推定を説明する。最尤推定は確率論から正当化できると言う長所がある。

さて、確率モデルがどのくらい実際の観測データに即しているかを**尤度（ゆうど）（likelihood）**と言い、観測されたデータをモデルに入力し、その出力をかけ合わせたもので定義されます。

例えば、 $N$ 個のデータ $x_i \ (i=1,\dots,N)$ が独立に観測されたとき、この観測データの下での確率モデル $f(x; \theta)$ の**尤度**は

$$
L(\theta) = \prod_{i=1}^N f(x_i; \theta)
$$

と計算されます。与えられたデータから、「どのようなデータがどのくらいよく観測されるか」を表す確率分布を推定（[注釈5](#note5)）するために、予め用意した確率モデルのパラメータを、それらの観測データの下での**尤度が最大**になるように決定する方法を、**最尤（さいゆう）推定（maximum likelihood estimation）**と言う。

上式の $\prod$ と言う記号は、 $\sum$ の掛け算版で、全ての値を掛け合わせると言う意味である。複数データに対する尤度は、 $1$ より小さな値の積となるため、結果は非常に小さな数になり、コンピュータでこの計算を行う際にはアンダーフローと言う問題が発生しやすくなる。また尤度を最大化したい場合、積の形の式の最大化は難しいことが知られている。そこで尤度の対数をとった**対数尤度（log likelihood）**を考えます。 $y = \log(x)$ は単調増加であるため、対数をとる前後で大小関係は変わらない。そのため対数尤度を最大にするときの $\theta$ は、元の尤度も最大にする。

$$
\log L(\theta) = \sum_{i=1}^N \log f(x_i; \theta)
$$

よって、この対数尤度を最大化するパラメータ $\theta$ を求めることができれば、その値が観測データ $x_i (i=1,\dots,N)$ の分布を最もよく表現する確率モデルのパラメータとなる。

### 例：コイントスのパラメータ推定

ここで、具体例として、コインの表・裏が出る確率を推定する問題を考えてみる。コインを投げて「表が出る」事象を $1$ に、「裏が出る」事象を $0$ に対応付ける確率変数を $X$ とする。このとき、 $p(X)$ をシンプルな確率モデル

$$
f(x; \theta) = \theta^x (1 - \theta)^{1 - x}
$$

で表現することにする（[注釈6](#note6)）。これは $x = 1$ のとき、すなわちコインが表であるとき $\theta$ をそのまま返し、 $x = 0$ のとき、すなわちコインが裏であるとき $1 - \theta$ を返すような関数となっている。ただし、 $0 \leq \theta \leq 1$ を満たすこととする。今、コインを $10$ 回投げ、以下の観測結果が得られたとする。

| $\ $ | 1回目 | 2回目 | 3回目 | 4回目 | 5回目 | 6回目 | 7回目 | 8回目 | 9回目 | 10回目 |
|:----:|:----:|:----:|:----:|:----:|:----:|:----:|:----:|:----:|:----:|:----:|
| X | 1 | 0 | 1 | 1 | 1 | 0 | 0 | 1 | 0 | 0 |

これらの観測データの下での確率モデルの尤度は

$$
\begin{aligned}
L(\theta) &=
\theta \cdot
(1 - \theta) \cdot
\theta \cdot
\theta \cdot
\theta \cdot
(1 - \theta) \cdot
(1 - \theta) \cdot
\theta \cdot
(1 - \theta) \cdot
(1 - \theta) \\
&= \theta^{5} \cdot (1 - \theta)^{5}
\end{aligned}
$$

である。対数尤度は、

$$
\log L(\theta) = 5 \log \theta + 5 \log \left( 1 - \theta \right)
$$

となる。これが最大となるときの $\theta$ は、この式を $\theta$ で微分した式を $0$ とおいて解析的に解けばよく、

$$
\begin{align}
\frac{5}{\theta} - \frac{5}{\left( 1 - \theta \right)} &= 0 \\
\therefore \theta = \frac{1}{2}
\end{align}
$$

と決定する。これが最尤推定である。

## 事後確率最大化推定（MAP推定）

前節で解説した最尤推定は、多くの場合で有用であるが、求めるパラメータに何らかの**事前知識**があっても、それを活かすことができない。そのため、サンプルサイズが小さい場合に、実際にはほとんどあり得ない結果が求まることがある。具体例を見てみる。

再び、コインの表・裏が出る確率を推定する例を考えます。コインを $5$ 回投げたところ、**たまたま** ${\bf 5}$ **回とも表が出た**とする。この場合、前節と同じ確率モデルを用いて尤度を計算し、最尤推定でモデルのパラメータを決定すると、 $0 \leq \theta \leq 1$ を満たしながら、今回の観測データの下での尤度 $\theta^5$ を最大にする $\theta$ は $1$ となる。これは「表が出る確率が $1$ 」すなわち**「裏面が出る確率は** $0$**」**と言う推定結果が得られてしまったことを意味する。もし「裏が出る確率も $0$ よりは大きいだろう」と言う事前知識を持っておりそれを活用できれば、今回のような場合でもよりよい推定ができそうである。

事前知識も考慮しながら、観測データに基づいて確率モデルのパラメータを推定する方法には、**事後確率最大化（maximum a posteriori, 以降 MAP）推定**がある。MAP 推定でも、対象のデータの確率分布を表す確率モデルのパラメータを、データを利用して決定するが、データだけでなく**パラメータも確率変数だと考える**点が最尤推定とは異なっている。パラメータを確率変数 $\Theta$ とすると、このパラメータがどのような値をとるかを表す分布 $p(\Theta)$ が導入できる。これを**事前分布（prior distribution）**と呼び、ここに「求めたいパラメータに対する事前知識」を反映させることができる。ここで、 $\Theta = \theta$ となる確率 $p(\Theta = \theta)$（以降は $p(\theta)$ と略記）をデータの確率モデル $f(x; \theta)$ とは別の確率モデル $g(\theta; \beta)$ で表せば、 $\beta$ を人為的に与えるか、なんらかの方法で決定しておくことで、「どのような $\theta$ が起こりやすいか」と言う事前知識を表現することができる。

MAP 推定では、観測データ $x_i \ (i=1,\dots,N)$ が観測されたと言う**条件の下で**最も確率が大きくなる $\theta$ を求めます。すなわち、 $p(\theta | x_1, \dots, x_N)$ を最大とする $\theta$ を求めます。これは「 $x_i \ (i=1,\dots,N)$ が観測された」と言う**結果**のもとで「データの確率分布を表すモデルのパラメータが $\theta$ であったことが**原因**である」確率を意味するので、**事後確率**である。ベイズの定理から、事後確率は

$$
p(\theta | x_1,\dots,x_N) = \frac{p(x_1,\dots,x_N | \theta) p(\theta)}{p(x_1,\dots,x_N)}
$$

と書けました。右辺に着目する。分子にある $p(x_1,\dots,x_N | \theta)$ を、確率モデル $f(x; \theta)$ を用いて $\prod_{i=1}^N f(x_i; \theta)$ と表すと、これは観測データ $x_i \ (i=1,\dots,N)$ の下での確率モデル $f(x; \theta)$ の**尤度**である。また、その右の $p(\theta)$ は、パラメータが $\theta$ と言う値になる**事前確率**でした。これが $g(\theta; \beta)$ と言う確率モデルで表されるとする。

今、事後確率を最大にするパラメータ $\theta$ を求めるために、右辺を最大化する $\theta$ を考えます。このとき、パラメータと無関係に決まる $p(x_1,\dots,x_N)$ を無視し

$$
p(x_1,\dots,x_N | \theta) p(\theta)
$$

だけに注目してこれを最大化するようにパラメータ $\theta$ を決定すると、その $\theta$ は求めたい左辺の事後確率を最大にする $\theta$ に一致する。上式は、尤度と事前分布の積になっている。このことから、**事後分布は尤度と事前分布の積に比例する**と言うことが分かる。

### 例：コイントスでのパラメータ推定

前節の最尤推定で用いたコイントスの例を再び考えます。
今度は MAP 推定を用いてパラメータを推定してみる。用いるデータは先程と同様の $10$ 回のコイントス結果である。
また、確率モデル $f(x; \theta)$ も同様に最尤推定の場合と同様のものを用いる。
MAP 推定では確率モデル $f(x;\theta)$ の他に、事前分布 $p(\theta)$ を設計する必要がある。
$p(\theta)$ の決め方は推定を行う人がどのような事前知識（もしくは信念）を持っているかによって自由に選択することができるが、ここでは事前分布を

$$
p(\theta) = 12\theta (1-\theta)^2
$$

と設定する（[注釈7](#note7)）。 グラフを書くと $p(\theta)$ は $\theta = 1/3$ で最大値をとることがわかる。これは「コイントスが行われる前には、実験者は $\theta=1/3$ が最もあり得る可能性である」すなわち、「このコインは表よりも裏の方が出やすい」と信じている（事前知識を持っている）と解釈することができる。

事後分布は $\theta$ の関数として $p(x_1, \ldots, x_N | \theta) p(\theta)$ に比例するのでした。
これを具体的に計算すると

$$
p(x_1, \ldots, x_N | \theta) p(\theta) = \theta^5 (1-\theta)^5 \times 12 \theta (1-\theta)^2 = 12 \theta^6 (1-\theta)^7
$$

となる。これを $\theta$ の関数として最大化する。
最尤推定の時と同様に、この値そのものではなく、対数を取った値を最大とする $\theta$ を求めます。

$$
\log p(x_1, \ldots, x_N | \theta) p(\theta) = 6\log \theta + 7 \log (1-\theta) + const.
$$

ここで， $const.$ は $\theta$ に依存しない定数（具体的には $\log 12$ ）で、値を最大にする $\theta$ を決定するのに影響を及ぼしない。
これを $\theta$ で微分したものが $0$ に等しいと言う方程式を立てると、

$$
\begin{align}
\frac{6}{\theta} - \frac{7}{1-\theta} = 0 \\
\therefore \theta = \frac{6}{13}
\end{align}
$$

と解くことができる．これが MAP 推定で得られた推定値である。

最尤推定で得られた推定値は $\theta = 1/2$ だったので、MAP 推定は最尤推定よりも低めに $\theta$ を推定していることがわかる。
これは事前分布 $p(\theta)$ により $\theta$ は $1/2$ より小さい値が出やすいと言う事前知識を入れていたことを反映している。逆に事前分布で大きい $\theta$ が出やすいと言う事前知識を入れれば、MAP 推定の値を最尤推定よりも大きくすることができる。

この例からも分かる通り、MAP 推定は事前分布の設定により得られる推定値が変化する。
この事は、MAP 推定の方が事前知識により柔軟なモデリングができる半面、誤った事前知識に基づいて事前分布を設計すると、推定値が実際のデータと乖離する可能性を持つことを意味する。

## 統計量

本節では、いくつかよく用いられる統計量を説明する。統計量とは、**観測されたデータの特徴を要約する数値**のことを指す。代表的な統計量として平均、分散、標準偏差を紹介する。

### 平均

**平均 (mean)** は、観測された数値を合計し、その数値の個数で割ったもののことを言う。たとえば、300 円、400 円、500 円の平均は、

$$
\frac{300 + 400 + 500}{3} = 400
$$

である。一般に、 $N$ 個のデータ $x_i \ (i=1,\dots,N)$ が観測されたとき、その平均は

$$
\begin{aligned}
\overline{x}
= \frac{x_1 + x_2 + \dots + x_N}{N}
= \frac{1}{N} \sum^{N}_{n=1} x_{n}
\end{aligned}
$$

と定義されます。
平均を表す記号として、 $\bar{x}$ や $\mu$ がよく用いられます。
データの分布において、平均はその重心に相当する値である。

### 分散

次に、**分散 (variance)** を紹介する。分散はよく $\sigma^2$ と表され、

$$
\sigma^2 = \frac{1}{N} \sum_{n=1}^N \left( x_n - \overline{x} \right)^2
$$

と定義されます。各データ点 $x_i \ (i=1,\dots,N)$ の値から、それらの平均 $\bar{x}$ を引き二乗した値（ $(x_i - \bar{x})^2 \ (i=1,\dots,N)$ ）の平均を計算している。これは、「データが自らの平均より平均的にどのくらいばらついているか」を表す。平均が同じデータでも、全てのデータが平均付近にある場合は分散は小さく、平均よりも極めて大きなデータ点や小さなデータ点が多数ある場合、分散は大きくなる。分散にはもう一種類ある。以下のようなものである。

$$
\begin{aligned}
s^2 = \frac{1}{N - 1} \sum_{n=1}^N \left( x_n - \overline{x} \right)^2
\end{aligned}
$$

始めに登場した $\sigma^2$ の定義では $\frac{1}{N}$ となっていた部分が $\frac{1}{N - 1}$ に変わっている。
前者は**標本分散 (sample variance)** といい、後者は**不偏分散 (unbiased variance)** と言う。
これらの式の導出は他の文献に譲るとして、ここではその使い分けについて説明する。

**図表**

例えば、全国の小学生の身長と体重の分散を調べたいとする。このとき、全国の小学生を一人の抜け漏れもなく調べたなら、集まったデータは**母集団 (population)** と呼ばれます。
一方、各都道府県の小学生を100人ずつ調べた場合、そのデータは**標本集団 (sample population)** と言う。
すなわち、母集団とは解析を行いたいデータ全ての集合を指し、標本集団とは母集団から抽出された一部のデータの集合を指す。一般に、標本集団のデータ数が少ないとき、標本分散は母集団の分散よりも小さくなることが知られている。不偏分散は、その差を補正することで、母集団の分散をより正確に推定するために用いる。不偏分散は抽出すデータの数（$N$）を増やせば、いずれ母集団の分散に一致する。また、$N$ が大きいと標本分散と不偏分散はほぼ一致するので、たくさんのデータ数をとることができる状況では、両者に大きな違いが生じないことも多々ある。

分散を利用すると、データのばらつきを定量評価することができるようになる。例えば、同じ現象を複数回観測する実験を行った際、結果のばらつきが大きければ、その観測方法には問題がある可能性がある。もしくは、同じだと思っていた現象は、実は観測のたびに異なる現象であった可能性がある。このように、多数の試行の結果がある値に集まっていることが望ましいような状況において、ばらつきの度合いを定量し評価することは重要である。

### 標準偏差

次に**標準偏差 (standard deviation)** を紹介する。
分散はデータの平均からの差の**二乗**の平均でした。そのため単位は元の単位を二乗したものになる。例えばデータの単位が ${\rm kg}$ であれば、分散の単位は ${\rm kg}^2$ になる。そこで、分散 $\sigma^2$ の平方根 $\sigma$ を計算することで、データと単位が等しくなり、解釈が容易になる。この $\sigma$ を標準偏差と呼ぶ。

練習問題で具体的な計算手順の確認を行う。以下の①と②のデータに対して、平均、分散、標準偏差を求める。ただし、今回は標本分散を使用することとする。

**図表**

①の解答は以下の通りである。

$$
\begin{aligned}
\bar{x} &= \frac{1}{5} \left( -2 -1 + 0 + 1 + 2 \right) = 0 \\
\sigma^{2} &= \frac{1}{5} \left\{ \left( -2 -0 \right)^{2} + \left( -1 -0 \right)^{2} + (0 - 0)^{2} + (1 - 0)^{2} + (2 - 0)^{2} \right \} \\
&= \frac{1}{5} \times 10 = 2 \\
\sigma &= \sqrt{2}
\end{aligned}
$$

②の解答は以下の通りである。

$$
\begin{aligned}
\overline{x} &= \frac{1}{5} ( -4 -2 + 0 + 2 + 4 ) = 0 \\
\sigma^2 &= \frac{1}{5}
\left\{ (-4 -0)^2 + (-2 -0)^2 + (0 - 0)^2 + (2 - 0)^2 + (4 - 0)^2 \right\} \\
&= \frac{1}{5} \times 40 = 8 \\
\sigma &= \sqrt{8} = 2 \sqrt{2}
\end{aligned}
$$

これより、②のケースの方が分散が大きく、データのばらつきが大きいことがわかる。

### 相関係数

最後に**相関係数 (correlation coefficient)** を紹介する。

2 種類のデータが得られている状況では、両者の関係性の解析がしばしば重要となる。
相関係数は両者の関連の度合いを定量的に測るのに用いる。

2 種類のデータ点がスカラー値で $N$ 個ずつある状況を考えます。それぞれを $x_n, y_n  \ (n=1,\dots,N)$ とした場合、相関係数の中でも良く用いられるピアソンの相関係数は以下のように定義されます。

$$
r = \frac{\sum_{n=1}^{N} (x_{n}-\bar{x})(y_{n}-\bar{y}) }{\sqrt{\left( \displaystyle \sum_{n=1}^N(x_{n}-\bar{x})^2 \right) \left( \displaystyle \sum_{n=1}^N(y_{n}-\bar{y})^2 \right) }}
$$

上式のように相関係数を表す記号は $r$ を用いるのが一般的である。
相関係数 $r$ は常に $-1 \leq r \leq 1$ になり、相関が認められるとき、 $r$の値が正の場合は**正の相関**があるといい、逆に負の値のときは**負の相関**があると言う。

2 種類のデータ間の相関が強いほど $r$ の絶対値は大きくなる。
しかし、「$r$ がいくつ以上ならば相関があると思って問題ない」と言う閾値はタスクごとに異なり、例えば $r=0.2$ から相関ありと判断してよいかは一概には言えない。本資料では説明を省略するが、無相関検定などの手法を利用することで客観的な判断を行うことができる。

**注釈 1**

ここでは概念の説明を簡単にするため、この例のように離散的な値をとる確率変数を考え、特に明示しない限り連続値の確率変数は考えないことにする。

[▲上へ戻る](#ref_note1)

**注釈 2**

$x$ は $1, 2, 3, 4, 5, 6$ のいずれか。すなわち $x \in \{1, 2, 3, 4, 5, 6\}$ である。

[▲上へ戻る](#ref_note2)

**注釈 3**

$y$ は 2 つ目のコインがとりうる状態で、この場合、「表」と「裏」と言う値のいずれか。

[▲上へ戻る](#ref_note3)

**注釈 4**

$x$ は 1 つ目のコインがとりうる状態で、この場合、「表」と「裏」と言う値のいずれか。

[▲上へ戻る](#ref_note4)

**注釈 5**

以降、このことを「データの分布を推定する」と言うことがある。また、観測されたデータのみから各データの発生確率（頻度とも捉えられる）を求めたものは**経験分布（empirical distribution）**とも呼ばれ、本節で説明しているのは正確にはこの経験分布を確率モデルで近似する方法である。

[▲上へ戻る](#ref_note5)

**注釈 6**

この関数には、ベルヌーイ分布と言う名前がついている。

[▲上へ戻る](#ref_note6)

**注釈 7**

先頭の $12$ は $p(\theta)$ $0$ から $1$ まで積分した値が $1$ となるように決めている。これにより、$p(\theta)$ が $0 \leq \theta \leq 1$ の上の確率分布となる。

[▲上へ戻る](#ref_note7)

# Step 1 の演習問題

本章では Step 1 で扱ったテーマについて演習問題を記する。
本章の演習問題には Step 1 で扱った知識だけで解けるものもあれば、外部の資料を調べる必要があるものもある。

## "2. Python 入門" の演習問題

### 問2.1 (組み込み関数)

Python には2章で紹介した以外にも数多くの組み込み関数が定義されている。組み込み関数を適切に使うことでコードを簡潔に記せます。`a=[4, 8, 3, 4, 1]` と言うリストに対して以下の操作を行う組み込み関数を[公式ドキュメント](https://docs.python.org/ja/3/library/functions.html)からそれぞれ探し、適用して下さい。すなわち、以下のコードセル中の `FUNC` の部分を適切な組み込み関数に置き換える。

- リスト `a` の長さを求める。
- リスト `a` に含まれる値の最大値を求める。
- リスト `a` に含まれる値の最小値を求める。
- リスト `a` に含まれる値の合計値を求める。
- リスト `a` をソートして、`[1, 3, 4, 4, 8]` と言うリストを返す。

```python
# 以下の FUNC と言う部分を組み込み関数に置き換える

a = [4, 8, 3, 4, 1]
res = FUNC(a)
print(res)
```

### 問2.2 (演算)

以下の演算や関数をそれぞれ評価したとき、結果の値と型が何になるか予想する。実際にコードを実行して、結果が予想と合うか確かめる。型の確認には `type()` 関数を使用する。

- `1.2 + 3.8`
- `10 // 100`
- `1 >= 0`
- `'Hello World' == 'Hello World'`
- `not 'Chainer' != 'Tutorial'`
- `all([True, True, False])`  (`all` の定義は[公式ドキュメントを参照](https://docs.python.org/ja/3/library/functions.html#all))
- `any([True, True, False])`  (`any` の定義は[公式ドキュメントを参照](https://docs.python.org/ja/3/library/functions.html#any))
- `abs(-3)`  (`abs` の定義は[公式ドキュメントを参照](https://docs.python.org/ja/3/library/functions.html#abs))
- `2 // 0`

```python
# ここにコードを書く

```

### 問2.3 (リストの基本操作)

機械学習では大量のデータを扱うことが多いため、リストの扱いに慣れておくと便利なことが多い。
`a=[4, 8, 3, 4, 1]` と言うリストに対して以下の操作を行うコードを書いて下さい。

- リスト `a` の先頭の要素を取り除いて、`[8, 3, 4, 1]` となるようにして下さい。
- リスト `a` の末尾の要素を取り除いて、`[4, 8, 3, 4]` となるようにして下さい。
- リスト `a` の末尾に `100` と言う値を追加して、`[4, 8, 3, 4, 1, 100]` となるようにして下さい。

```python
# ここにコードを書く

```

### 問2.4 (リスト内包表記)

**リスト内包表記**はリストを生成するための簡潔な手段である。例えば、平方数のリスト `[0, 1, 4, 9, 16, ...]` を構成したいとき、
```python
squares = []
for x in range(10):
    squares.append(x ** 2)
```
と書く代わりに、
```python
squares = [x ** 2 for x in range(10)]
```
と書くことができる。リスト内包表記は一般に `[(式) for (変数) in (iterableオブジェクト)]` と言う構文を取る。リスト内包表記の一般的な説明は[公式ドキュメント](https://docs.python.org/ja/3/tutorial/datastructures.html#list-comprehensions)を参照して下さい。リスト内包表記で `in` の後に続く iterable オブジェクトは `range` である必要はなく、例えばリストを指定できる。

```python
a = [4, 8, 3, 4, 1]
squares = [x ** 2 for x in a]
print(squares)  # => [16, 64, 9, 16, 1]
```

以下の問いに答えて下さい。

(1) `a=[4, 8, 3, 4, 1]` と言うリストに対し、要素が偶数なら `0`, 奇数なら `1` に変換するコードをリスト内包表記を用いて書いて下さい。この結果、このリストは `[0, 0, 1, 0, 1]` に変換されるべきである。

(2) (1) で書いたコードと組み込み関数を組み合わせて、リスト `a` に含まれる奇数の個数を数えるコードを書いて下さい。

(3) リスト内包表記では、`if` 文を用いることで条件を満たす要素だけをリストに残すことができる。例えば
```python
b = [x for x in range(10) if x > 5]
```
と記すと、`b` は要素が `5` より大きいもののみが残り `[6, 7, 8, 9]` となる。

リスト内包表記を使ってリスト `a` から奇数の要素だけを残すコードを書いて下さい。

```python
# ここにコードを書く

```

### 問2.5 (文字列)

Python では文字列型に対して便利な組み込み関数が多数定義されている([公式のドキュメント](https://docs.python.org/ja/3/library/stdtypes.html#text-sequence-type-str))。組み込み関数を使って以下の処理を行って下さい。

(1) [str.join()](https://docs.python.org/ja/3/library/stdtypes.html#str.join) を使って、`0` から `99` までの数をスペース区切りで並べた文字列 `"0 1 2 3 4 ... 99"` を構成して下さい。

(2) [str.format()](https://docs.python.org/ja/3/library/stdtypes.html#str.format) を使って `float` の値 `(1.0 / 7.0)` の小数点以下9桁までを表示して下さい。

```python
# ここにコードを書く

```

### 問2.6 (クラス)

クラスを実装する練習として、データを管理するクラスを実装してみる。
次のメソッドを全て持つクラス `DataManager` を記述して下さい。

* `__init__(self, x, y, z)`: 3つの数 `x`, `y`, `z` をコンストラクタで受け取り、インスタンスの属性でそれぞれの値を記憶する。
* `add_x(self, delta)`: `x` に `delta` だけ足して、値を更新する。
* `add_y(self, delta)`: `y` に `delta` だけ足して、値を更新する。
* `add_z(self, delta)`: `z` に `delta` だけ足して、値を更新する。
* `sum(self)`: `x`, `y`, `z` の3つの数の合計値を返す。

このクラスを使って以下のようなコードが書けるものとする。

```python
data_manager = DataManager(2, 3, 5)
print(data_manager.sum())  # => 10
data_manager.add_x(4)      # => data_manager.x の値が 2 から 6 に更新される
print(data_manager.sum())  # => 14
data_manager.add_y(0)      # => data_manager.y の値が 3 から 3 に更新される
print(data_manager.sum())  # => 14
data_manager.add_z(-9)     # => data_manager.z の値が 5 から -4 に更新される
print(data_manager.sum())  # => 5
```

```python
# ここにコードを書く

```

### 問2.7 (関数呼び出し)
以下で定義される関数 `f`, `g` があるとする。

```python
def f(a):
    a = [6, 7, 8]

def g(a):
    a.append(1)
```

これらに対し、次のコードの実行結果がどうなるか予想して下さい。実際にコードを実行して予想と一致しているか確認し、なぜそのような結果になったのか説明して下さい。

```python
def somefunction():
    a0 = [1, 2, 3]
    f(a0)
    print(a0)

    a1 = [1, 2, 3]
    g(a1)
    print(a1)

somefunction()
```

```python
# ここにコードを書く

```

### 問2.8 (制御構文)

2以上の整数 `p` が素数であるとは、「どんな `2` 以上 `p-1` 以下の整数 `k` に対しても `p` は `k` で割り切れない」が成り立つことを指す。素数を小さい順から列挙すると、`2`, `3`, `5`, `7`, `11`, `13`, `17`, ... となる。
チュートリアルで学んだ制御構文である `if` や `for` を用いて、`2` から `100` からまでに含まれる素数を列挙して下さい。

```python
# ここにコードを書く

```

## "4. 微分の基礎" の演習問題

ここからは、紙と鉛筆を用意する。

### 問4.1 (導関数)
導関数の定義 $f'(x) = \lim_{h \rightarrow 0} \frac{f(x+h)-f(x)}{h}$ を用いて以下の関数 $f_1(x), f_2(x)$ の導関数 $f^{'}_1(x), f^{'}_2(x)$ をそれぞれ求めて下さい。

* $f_1(x) = x^3$.
* $f_2(x) = \sqrt{x}$. (ヒント: 分母と分子に $(\sqrt{x+h}+\sqrt{x})$ を掛けて式を整理してみて下さい)

### 問4.2 (線形性)
微分の線形性 $\left( cf(x) \right)^{'} = c f'(x)$, $\left( f(x) + g(x) \right)^{'} = f^{'}(x) + g^{'}(x)$ を用いて、以下の関数の導関数を求めて下さい。

* $f_1(x) = 2x^2-5x+1$
* $f_2(x) = \sum_{k=1}^{123} (k^2+1)x^k$

### 問4.3 (積の微分)
積の微分 $\bigl( f(x) \cdot g(x) \bigr)^{'} = f^{'}(x)g(x) + f(x)g^{'}(x)$ を使って以下の関数を微分して下さい。

* $f_1(x) = x \cdot x$.
* $f_2(x) = x \cdot x^2$.
* $f_3(x) = x \cdot x^3$.

これを繰り返していくと、$g(x) = x^{100}$ に対して $g^{'}(x) = 100x^{99}$ などが成り立つことを確かめて下さい。

### 問4.4 (合成関数の微分)
合成関数の微分則 $\frac{d}{dx} f(g(x)) = \frac{df(u)}{du}\frac{du}{dx}$ ($u=g(x)$) を使って以下の関数を微分して下さい。

* $f_1(x) = (x+1)^3$.
* $f_2(x) = (4x)^3$.
* $f_3(x) = \exp(2x-1)$.
* $f_4(x) = \exp(-x^2)$.
* $f_5(x) = 2^x$.  (ヒント: $2^x = \exp(\log(2) x)$ を利用する)

### 問4.5 (合成関数の微分)
$f(x) = x^2 + 1$, $g(x) = f(f(x))$ とする。

(1) $g(x) = x^4 + 2x^2 + 2$ となることを確認して下さい。また、これより $g'(x) = 4x^3 + 4x$ となることを確認して下さい。

(2) 一方で、合成関数の微分則によって $g'(x)$ を計算し、(1) で求めた導関数と一致することを確認して下さい。

(3) $h(x) = f(f(f(x)))$ とする。合成関数の微分によって $h'(x)$ を計算して下さい。(ヒント: $h(x)=f(g(x))$ であることを利用する)

### 問4.6 (指数関数・対数関数)
指数関数 $\exp(x)$ と対数関数 $\log(x)$ の導関数は以下で定まる。

$$
\begin{align}
\exp^{'}(x) &= \exp(x). \\
\log^{'}(x) &= \frac{1}{x}. \\
\end{align}
$$

このことをプログラムを用いた実験によって確認してみる。
**数値微分**は導関数を近似的に計算する手法である。導関数の定義

$$f^{'}(x) = \lim_{h \rightarrow 0} \frac{f(x+h)-f(x)}{h}$$

において、極限を取る代わりにある微小な値 $\Delta h$ を $h$ に代入し、

$$
f'(x) \approx \frac{f(x+\Delta h)-f(x)}{\Delta h}
$$

として計算することによって導関数の値を近似する方法が数値微分である。具体的な $x$ の値に対する $\exp(x)$ の微分を数値微分によって計算するコードは以下のようになる。

```python
import math  # exp を呼び出すために math モジュールをインポート

def f(x):
    return math.exp(x)

def dfdx_approx(x):
    dh = 0.0001
    return (f(x + dh) - f(x)) / dh
```

(1) `x=-3,-2,-1,0,1,2,3` に対して数値微分の関数 `dfdx_approx` を呼び出し、その結果得られた値と正確な微分の値($\exp^{'}(-3),\ldots,\exp^{'}(3)$)とを比較して下さい。

(2) 対数関数 $\log(x)$ についても同様の実験を行い、`x=0.25,0.5,1,2,4,8` に対して比較して下さい。Python から対数関数を呼び出す場合、`math.log` を使用する。

```python
# ここにコードを書く

```

### 問4.7 (ニューラルネットワークの関数の微分)
ニューラルネットワークのモデルでよく扱われる関数の導関数を計算してみる。

* $\mathrm{ReLU}(x) = \max(x, 0)$.
* $\tanh(x) = \frac{e^x - e^{-x}}{e^x + e^{-x}}$.  (注意: 商の微分則 $\bigl(\frac{f(x)}{g(x)}\bigr)^{'}=\frac{f^{'}(x)g(x)-f(x)g^{'}(x)}{g(x)^2}$ を用いる)
* $\mathrm{Sigmoid}(x) = \frac{1}{1 + e^{-x}}$.
* $\mathrm{Softplus}(x) = \log(1+e^x)$.

### 問4.8 (偏微分)
(1) 2変数関数 $f(x, y) = |x| + |y|$ に対して偏微分 $\frac{\partial}{\partial x}f(x,y)$, $\frac{\partial}{\partial y}f(x,y)$ を求めて下さい。

(2) 2変数関数 $f(x, y) = |x + y|$ に対して偏微分 $\frac{\partial}{\partial x}f(x,y)$, $\frac{\partial}{\partial y}f(x,y)$ を求めて下さい。

## "5. 線形代数の基礎" の演習問題

### 問5.1 (プログラムにおけるベクトル・行列の計算)

Python コード上でベクトルや行列に関する演算を行うことを考えてみる。ベクトルは `float` のリスト、行列は `float` のリストのリストによって表すことができる。例えば、

$$
{\bf x}=\begin{bmatrix}
3 \\
7 \\
2
\end{bmatrix}, \
{\bf A}=\begin{bmatrix}
1 & 2 & 3 \\
4 & 5 & 6
\end{bmatrix}
$$

と言うベクトルと行列はそれぞれ `[3, 7, 2]` と `[[1, 2, 3], [4, 5, 6]]` と Python コード上で表すことができる。

(1) 2つのベクトル ${\bf x}$, ${\bf y}$ を受け取り、その和 ${\bf x} + {\bf y}$ を返す関数を書いて下さい。コードは例えば以下のようになる。

```python
def vector_sum(x, y):
    # ...

x = [1, 2, 3]
y = [8, 1, 2]
answer = vector_sum(x, y)
print(answer)  # => [9, 3, 5]
```

(2) 2つの行列 ${\bf X}$, ${\bf Y}$ を受け取り、その和 ${\bf X} + {\bf Y}$ を返す関数を書いて下さい。コードは例えば以下のようになる。

```python
def matrix_sum(X, Y):
    # ...

X = [[1, 2, 3],
     [4, 5, 6]]
Y = [[8, 1, 2],
     [-1, 0, -2]]
answer = matrix_sum(X, Y)
print(answer)  # => [[9, 3, 5], [3, 5, 4]]
```

(3) 行列 ${\bf X}$ とベクトル ${\bf y}$ を受け取り、その積 ${\bf X}{\bf y}$ を返す関数を書いて下さい。

```python
def matrix_vector_product(X, y):
    # ...

X = [[1, 2, 3],
     [4, 5, 6]]
y = [8, 1, 2]
answer = matrix_vector_product(X, y)
print(answer)  # => [16, 49]
```

(4) 2つの行列 ${\bf X}$, ${\bf Y}$ を受け取り、その積 ${\bf X}{\bf Y}$ を返す関数を書いて下さい。

```python
def matrix_product(X, Y):
    # ...

X = [[1, 2, 3],
     [4, 5, 6]]
Y = [[8, 1],
     [-1, 0],
     [0, 1]]
answer = matrix_product(X, Y)
print(answer)  # => [[6, 4], [27, 10]]
```

(5) 行列 ${\bf X}$ を受け取り、その転置 ${\bf X}^{\rm T}$ を返す関数を書いて下さい。

```python
def matrix_transpose(X):
    # ...

X = [[1, 2, 3],
     [4, 5, 6]]
answer = matrix_transpose(X)
print(answer)  # => [[1, 4], [2, 5], [3, 6]]
```

```python
# ここにコードを書く

```

### 問5.2 (ベクトルの微分)
${\bf x}$ を次元数 $n$ のベクトル、${\bf A}$ を $n \times n$ の正方行列とする。

$$
{\bf x}=\begin{bmatrix}
x_{1} \\
\vdots \\
x_{n}
\end{bmatrix}, \
{\bf A}=\begin{bmatrix}
a_{11} & \ldots & a_{1n} \\
\vdots &        & \vdots \\
a_{n1} & \ldots & a_{nn}
\end{bmatrix}
$$

二次形式に関する微分 $\frac{\partial}{\partial {\bf x}} \left( {\bf x}^{\rm T}{\bf A}{\bf x} \right) = {\bf x}^{\rm T} \left( {\bf A} + {\bf A}^{\rm T} \right)$ を証明してみる。

(1) ${\bf x}^{\rm T}{\bf A}{\bf x} = \sum_{i=1}^n \sum_{j=1}^n a_{ij} x_i x_j$ であることを示して下さい。さらに、これより以下を示して下さい。
$$
{\bf x}^{\rm T}{\bf A}{\bf x} = a_{11} x_1^2 + \left( \sum_{i=2}^n (a_{1i} + a_{i1}) x_i \right) x_1 + \sum_{i=2}^n \sum_{j=2}^n x_i x_j a_{ij}.
$$

(2) 偏微分 $\frac{\partial}{\partial x_1} \left( {\bf x}^{\rm T}{\bf A}{\bf x} \right)$ を計算し、$\sum_{i=1}^n (a_{1i} x_i + a_{i1} x_i)$ となることを示して下さい。

(3) 一般に、$k=1,\ldots,n$ に対して $\frac{\partial}{\partial x_k} \left( {\bf x}^{\rm T}{\bf A}{\bf x} \right) = \sum_{i=1}^n (a_{ki} x_i + a_{ik} x_i)$ となることを示して下さい。これによって $\frac{\partial}{\partial {\bf x}} \left( {\bf x}^{\rm T}{\bf A}{\bf x} \right) = {\bf x}^{\rm T} \left( {\bf A} + {\bf A}^{\rm T} \right)$ が成り立つことを確かめて下さい。

### 問5.3 (ベクトルを入力とする関数の微分)

$f, g$ をベクトルを入力とする実数値関数とする。
微分について以下の性質が成り立つことを示して下さい。

* $\frac{\partial}{\partial {\bf x}}(f({\bf x}) + g({\bf x})) = \frac{\partial}{\partial {\bf x}}f({\bf x}) + \frac{\partial}{\partial {\bf x}}g({\bf x})$.
* $c$ を任意の実数とするとき、$\frac{\partial}{\partial {\bf x}}(cf({\bf x})) = c\frac{\partial}{\partial {\bf x}}f({\bf x})$.
* $c$ を任意の実数、${\bf b}$ を任意のベクトルとするとき、$\frac{\partial}{\partial {\bf x}}f(c{\bf x} + {\bf b}) = c\frac{\partial}{\partial {\bf y}}{\bf f}({\bf y})$. (ここで ${\bf y}=c{\bf x}+{\bf a}$ とする。)

### 問5.4 (ベクトルを入力とする関数の微分)

${\bf x}$ を $n$ 次元ベクトルとする。
以下の関数 $f$ に対するベクトルの微分 $\frac{\partial}{\partial {\bf x}}f({\bf x})$ を計算して下さい。

* $f({\bf x}) = \max(x_1, x_2, \ldots, x_n)$.

* $f({\bf x}) = \sqrt{x_1^2 + x_2^2 + \ldots + x_n^2}$.

* $f({\bf x}) = |x_1 + x_2 + \ldots + x_n|$.

### 問5.5 (多変数関数の合成関数の微分)

3次元ベクトルに対するベクトル値関数 ${\bf f}$ を以下によって定義する。
$$
{\bf f}(\begin{bmatrix}
x_{1} \\
x_{2} \\
x_{3}
\end{bmatrix}) = \begin{bmatrix}
x_{2}^2 \\
x_{3}^2 \\
x_{1}^2
\end{bmatrix}.
$$

(1) ${\bf f}({\bf x})$ のヤコビ行列 $\frac{\partial}{\partial {\bf x}}{\bf f}({\bf x})$ を計算して下さい。

(2) ${\bf f}({\bf f}({\bf x}))$ を計算して下さい。

(3) ${\bf f}({\bf f}({\bf x}))$ のヤコビ行列 $\frac{\partial}{\partial {\bf x}}{\bf f}({\bf f}({\bf x}))$ を、(1) の結果を用いて計算して下さい。

(4) $\frac{\partial}{\partial {\bf x}}{\bf f}({\bf f}({\bf x}))$ を合成関数の微分則 $\frac{\partial}{\partial {\bf x}} {\bf f}( {\bf g}({\bf x}))  = \frac{\partial {\bf f}}{\partial {\bf u}}({\bf u}) \frac{\partial {\bf g}}{\partial {\bf x}}({\bf x})$ (${\bf u}={\bf g}({\bf x})$) によって計算し、結果が (3) と一致することを確認して下さい。

### 問5.6 (多変数関数の合成関数の微分)
${\bf A}$, ${\bf B}$ を $n \times n$ 行列とする。$n$ 次元ベクトル ${\bf x}$ に対して ${\bf f}({\bf x})={\bf A}{\bf x}$, ${\bf g}({\bf x})={\bf B}{\bf x}$ とする。

合成関数の微分則を用いて $\frac{\partial}{\partial {\bf x}}{\bf g}({\bf f}({\bf x})) = {\bf B}{\bf A}$ を示して下さい。

### 問5.7 (多変数関数の合成関数の微分)

(1) $f(y, z) = 2y-3z$ とする。このとき、1変数関数 $g(x)$ と $h(x)$ に対して

$$
\frac{d}{dx}f(g(x), h(x)) = 2g^{'}(x)-3h^{'}(x)
$$

であることを確認して下さい。

(2) $f(y, z) = yz$ とする。このとき $\frac{d}{dx}f(g(x), h(x)) = g^{'}(x)h(x) + g(x)h^{'}(x)$ であることを確認して下さい。

(3) 2変数実数値関数 $f(y, z)$ と1変数関数 $g(x), h(x)$ に対し以下が成り立つことを合成関数の微分則 $\frac{\partial}{\partial {\bf x}} {\bf f}( {\bf g}({\bf x}))  = \frac{\partial {\bf f}}{\partial {\bf u}}({\bf u}) \frac{\partial {\bf g}}{\partial {\bf x}}({\bf x})$ (${\bf u}={\bf g}({\bf x})$) を用いて示して下さい。

$$
\frac{d}{dx}f(g(x), h(x)) = \frac{\partial f}{\partial y}(y, z) \cdot g^{'}(x) + \frac{\partial f}{\partial z}(y, z) \cdot h^{'}(x)
$$

ここで、$y=g(x)$, $z=h(x)$ とする。この結果が (1) と (2) の式の一般化になっていることを確かめて下さい。

(4) 平面上を移動する点があり、時刻 $t$ の点の座標 $(x(t), y(t))$ は $x(t)=t^2+t+1, y(t)=t^2-t+1$ であるとする。座標 $(x,y)$ にいるとき、点は $E(x,y)=\exp(\frac{1}{\sqrt{x^2+y^2}})$ のエネルギーを持っているとする。エネルギーの時間に関する微分 $\frac{\partial}{\partial t}E(x(t),y(t))$ を (3) の結果を用いて求めて下さい。

### 問5.8 (多変数関数の合成関数の微分)
ベクトル値関数 ${\bf f}$ を以下で定義する。

$$
{\bf f}(\begin{bmatrix}
z \\
w
\end{bmatrix}) = \begin{bmatrix}
\frac{e^z}{e^{z+w}} \\
\frac{e^w}{e^{z+w}}
\end{bmatrix}.
$$

${\bf X}$ を $2 \times N$ 行列、${\bf y}$ を $N$ 次元ベクトルとする。
偏微分 $\frac{\partial}{\partial x_{ij}}{\bf f}({\bf X}{\bf y})$ を計算して下さい。ここで、$x_{ij}$ は ${\bf X}$ の $(i,j)$ 成分とする。

## "6. 確率・統計の基礎" の演習問題

### 問6.1 (同時分布・周辺確率)

偏りのあるコイン ${\rm A}$ と ${\rm B}$ がある。
コイン ${\rm A}$ を振ったときに表が出る確率は1/4、裏が出る確率は3/4である。コイン ${\rm B}$ を振ったときに表が出る確率は2/3、裏が出る確率は1/3である。

この二つのコインのうちどちらか一つを等しい確率でランダムに選び、選んだ方のコインを振ると言う試行を考えます。
選んだコインが ${\rm A}$ と ${\rm B}$ どちらだったかを表す確率変数を $X$、コインを振った結果(表裏)を表す確率変数を $Y$ とする。

(1) 同時確率 $p(X={\rm A}, Y=表)$, $p(X={\rm A}, Y=裏)$, $p(X={\rm B}, Y=表)$, $p(X={\rm B}, Y=裏)$ をそれぞれ計算して下さい。

(2) 同時確率を周辺化して、確率 $p(Y=表)$ と $p(Y=裏)$ を計算して下さい。

### 問6.2 (条件付き確率)

問6.1 の試行で条件付き確率 $p(Y=表 \mid X={\rm A})$ を計算して下さい。

### 問6.3 (ベイズの定理)

(1) 問6.1 の試行で事後確率 $p(X={\rm A} \mid Y=表)$, $p(X={\rm B} \mid Y=表)$, $p(X={\rm A} \mid Y=裏)$, $p(X={\rm B} \mid Y=裏)$ をそれぞれ計算して下さい。

(2) 問6.1 の試行を行った後、コインは表が出たとする。この後さらに同じコインを振ったときに再び表が出る確率を計算して下さい。

### 問6.4 (ベイズの定理)

一様な確率で1から6までの数が出るサイコロがある。
サイコロを何回か連続で振る試行を考えます。サイコロを振った後、直前に出た数より大きい数が出たときに「ラッキーである」と呼ぶことにする。
例えばサイコロを5回振って 2,5,3,4,4 と順に出た場合、2回目と4回目はラッキーであるが、それ以外はラッキーではない。

いま、サイコロを 10 回振って一度もラッキーではなかったとする。このとき、次にサイコロを振ってラッキーになる確率はいくらになるでしょうか。プログラムを使って分析してみて下さい。

```python
# ここにコードを書く

```

### 問6.5 (尤度と最尤推定)

偏りのあるサイコロの出る目の確率を推定する問題を考えます。サイコロを振ったときに出る数を表す確率変数を $X$ とする。確率モデルのパラメータを $\theta=(\theta_1, \theta_2, \theta_3, \theta_4, \theta_5, \theta_6)$ として、確率 $p(X=x)$ を

$$
f(x; \theta) = \theta_x
$$

によってモデル化する。ここで、パラメータは $\theta_1, \ldots, \theta_6 \ge 0$ かつ $\theta_1+\ldots+\theta_6=1$ を満たさなくてはならないとする。

いま、サイコロを60回振って、1の目が30回、それ以外の目が6回出たとする。

(1) 観測データに対する対数尤度を求めて下さい。

(2) プログラムを用いて、$\theta=(\theta_1, \ldots, \theta_6)$ に様々な値を入れた場合に対数尤度がどのようになるかを観測して下さい。$\theta$ がどのようなときに対数尤度が大きくなるか予想する。

```python
# ここにコードを書く

```

### 問6.6 (尤度と最尤推定)

ポアソン分布は正の実数 $\lambda>0$ をパラメータとして持つ分布である。$0$ 以上の整数値を取る確率変数 $X$ が以下の確率値に従うとき、$X$ はポアソン分布に従うと言う。

$$p(X=k)=\frac{\lambda^k e^{-\lambda}}{k!} \; \; \; (k=0,1,2,\ldots).$$

いま、ある交差点で特定の時間帯に存在する歩行者の人数のをポアソン分布でモデル化することを考えます。
$X$ を特定の時間帯に存在する歩行者の人数を表す確率変数とする。確率 $p(X=k)$ は上記のポアソン分布に従うとする。

20日間の観測結果によると、$i$ 日目には $10+i$ 人の歩行者を観測したことが分かっているとする。($i=1,2,\ldots,20$)

(1) 観測データに対する対数尤度を求めて下さい。

(2) 対数尤度を最大にする $\lambda$ の値を求めて下さい。

(3) (2) で求めた $\lambda$ をパラメータとして用いたとき、$k=0,1,\ldots,50$ に対して $p(X=k)$ をプログラムを用いて計算して下さい。なお、累乗 $\lambda^k$ の計算には組み込み関数の `pow` を、階乗 $k!$ の計算には `math` モジュールにある `math.factorial` を用いると便利である。

```python
# ここにコードを書く

```

### 問6.7 (事後確率最大化推定(MAP推定))

6章の例6.7.1 にあるコイントスの試行で、事前確率 $p(\theta)$ を以下のように変更した場合にどうなるかを考えてみる。

$$
p(\theta)=\begin{cases}
3 & (1/3 \le \theta \le 3/2) \\
0 & (\text{otherwise})
\end{cases}
$$

コインを10回振って9回表が出て1回裏が出たとき、MAP 推定によってパラメータ $\theta$ を推定して下さい。

### 問6.8 (統計量)

生徒が100人いる学校で期末試験をした結果、科目Aと科目Bの点数は以下のような結果になりました。

* 科目A: 20点の生徒が50人、80点の生徒が50人
* 科目B: 0点の生徒が1人、1点の生徒が1人、2点の生徒が1人、…、99点の生徒が1人

この二つの科目について、生徒の点数の平均と標準偏差をそれぞれ計算して下さい。プログラムを用いてもよい。

この例から分かるように、データのばらつきが非常に異なる性質をもっていても平均や標準偏差が近い値になることがある。

```python
# プログラムを用いる場合はここにコードを書く

```