Chainerチュートリアル Step1演習問題の解答1　

##背景

データサイエンスを始めるにあたり、[Chainer Tutorial](https://tutorials.chainer.org/ja/tutorial.html)をやりました。
初学者にもわかりやすい文章で、数学やpythonの基本から教えてくれるので、機械学習の入門にはおすすめだと思います（しかも無料！）。
準備編の最後に演習問題がついていますが、復習がてら解答をまとめ、投稿しようと思った次第です。

Chainerチュートリアル Step1演習問題の解答1（本記事）　→ 問題2, 4
Chainerチュートリアル Step1演習問題の解答2　→ 問題5, 6

##問2.1（組み込み関数）

```python

a = [4, 8, 3, 4, 1]

#リストaの長さを求める
res = len(a)
print(res)

#リストaに含まれる値の最大値を求める。
res = max(a)
print(res)

#リストaに含まれる値の最小値を求める。
res = min(a)
print(res)

#リストaに含まれる値の合計値を求める。
res = sum(a)
print(res)

#リストaをソートして、[1, 3, 4, 4, 8] というリストを返す。
res = sorted(a)
print(res)
```

##問2.3（リストの基本操作）

```python

#リストaの先頭の要素を取り除いて、[8, 3, 4, 1] となるようにして下さい。
a = [4, 8, 3, 4, 1]
a.pop(0)
print(a)

#リストaの末尾の要素を取り除いて、[4, 8, 3, 4] となるようにして下さい。
a = [4, 8, 3, 4, 1]
a.pop()
print(a)
```

配列の削除にはpopメソッドを使います。引数xを指定して、pop(x)とすると、インデックスがxに等しい場所の要素を取り除きます。
引数に何も指定しない場合は、デフォルトで末尾の要素1つを削除します。

```python

#リストaの末尾に 100 という値を追加して、[4, 8, 3, 4, 1, 100] となるようにして下さい。
a = [4, 8, 3, 4, 1]
a.append(100)
print(a)
```
appendメソッドは末尾に引数の値を追加します。

ちなみに、先頭に追加したい時はinsertメソッドを用いて、第一引数に追加したい場所、第二引数に追加したい要素を指定します。

```python

a = [4, 8, 3, 4, 1]
a.insert(0, 100)
print(a)
```

##問2.4（リスト内包表記）

#####1. a=[4, 8, 3, 4, 1] というリストに対し、要素が偶数なら 0, 奇数なら 1 に変換するコードをリスト内包表記を用いて書いて下さい。この結果、このリストは [0, 0, 1, 0, 1] に変換されるべきです。

```python

a=[4, 8, 3, 4, 1]

def convert(list):
    result = [0 if x % 2 == 0 else 1 for x in list]
    print(result)

convert(a)
```

#####2. 1.で書いたコードと組み込み関数を組み合わせて、リスト a に含まれる奇数の個数を数えるコードを書いて下さい。

1の関数で、奇数は1・偶数は0に変換されてますから、変換後の配列の全ての要素を足した数は、リストaに含まれる奇数の個数と等しくなるはずです。

```python
a=[4, 8, 3, 4, 1]

def odd_num(list):
    result = [0 if x % 2 == 0 else 1 for x in list]
    print(sum(result))

odd_num(a)
```

#####3.リスト内包表記を使ってリスト a から奇数の要素だけを残すコードを書いて下さい。

```python
a=[4, 8, 3, 4, 1]

def odd_only(list):
    result = [x for x in list if x % 2 == 1]
    print(result)

odd_only(a)
```

##問2.5（文字列）

#####1. str.join() を使って、0 から 99 までの数をスペース区切りで並べた文字列 "0 1 2 3 4 ... 99" を構成して下さい。

joinメソッドは、文字列に対する組み込み関数です。引数に配列を与えることで、配列内の要素を文字列で区切った、一つの文字列を形成します。

```python

a = [str(x) for x in range(100)] #[0,1,2, ・・・, 98, 99]という配列を作る

str = ' '.join(a) #半角スペースに対してjoinを使うことで、配列要素をスペースで区切った１つの文字列を作る
print(str)
```

#####2. str.format() を使って float の値 (1.0 / 7.0) の小数点以下9桁までを表示して下さい。

formatメソッドは、文字列内の{  }で囲まれたエリアに対し、引数で受けた値を埋め込みます。
{インデックス番号：書式設定}としてかき、インデックス番号は位置を、書式設定は桁数などを指定できます。
インデックス番号は省略できます。

```python

sentence = "{0}は{1}です".format("クジラ", "哺乳類")
print(sentence)

>>クジラは哺乳類です
```
小数点を指定する時は、{: .数字f}とします。

```python

num = 1.0/7.0

print('{0:.9f}'.format(num)) #インデックス番号を省略し、print('{:.9f}'.format(num))でもok
```

##問2.6（クラス）

```python

class DataManager:
    #3つの数 x, y, z をコンストラクタで受け取り、インスタンスの属性でそれぞれの値を記憶する。
    def __init__(self, x, y, z):
            self.x = x
            self.y = y
            self.z = z

    #add_x(self, delta): x に delta だけ足して、値を更新する。
    def add_x(self, delta):
            self.x += delta

    #add_y(self, delta): y に delta だけ足して、値を更新する。
    def add_y(self, delta):
            self.y += delta

    #add_z(self, delta): z に delta だけ足して、値を更新する。
    def add_z(self, delta):
            self.z += delta

    #sum(self): x, y, z の3つの数の合計値を返す。
    def sum(self):
        return self.x + self.y + self.z
```

##問2.8（制御構文）

```python
list = [i+2 for i in range(98)] #2~100までのリスト
prime_numbers = [] #素数を格納するリスト

for a in list: 
    k = a - 1 #2~98までの数字について、自分自身未満の値で割っていくのを繰り返す
    while k > 1:
        if a % k == 0: #途中で割り切れる数字が出現したら素数ではないので終了
          break
        else:
            k -= 1
    if k == 1: #途中で割り切れる数字がなく、kが1となるまで下がりきれたら、それは素数である
        prime_numbers.append(a)
    
print(prime_numbers)
```

##問4.1（導関数）
![スクリーンショット 2020-11-04 10.25.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/584114/738d7e3a-b33c-d0a9-e2e7-176ec5f3b13f.png)

##問4.2（線形性）

![スクリーンショット 2020-11-04 10.33.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/584114/13d614f9-3aaf-7e90-5545-1eb9e0267737.png)

##問4.3（積の微分）
![スクリーンショット 2020-11-04 10.39.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/584114/0e29641b-50ca-6176-2673-19ed21db67cb.png)

##問4.4（合成関数の微分）

![スクリーンショット 2020-11-04 11.05.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/584114/0968a3a4-c054-d1ef-1064-d5369b1ae24b.png)

##問4.5（合成関数の微分）
#####1.𝑔(𝑥)=𝑥^4+2^𝑥2+2  となることを確認して下さい。また、これより 𝑔′(𝑥)=4𝑥3+4𝑥 となることを確認して下さい。

![スクリーンショット 2020-11-04 12.34.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/584114/24c7606b-1ba4-670c-98fb-32b70fbb8ab5.png)

#####2.一方で、合成関数の微分則によって 𝑔′(𝑥) を計算し、(1) で求めた導関数と一致することを確認して下さい。
![スクリーンショット 2020-11-04 12.32.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/584114/9e49e3e2-8082-494a-fe7e-a491ff36770c.png)

1.で求めた式と一致しています。

#####3.ℎ(𝑥)=𝑓(𝑓(𝑓(𝑥)))  とします。合成関数の微分によって ℎ′(𝑥) を計算して下さい。

![スクリーンショット 2020-11-04 12.33.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/584114/0788cc2a-22e8-fded-a357-f8b7ef3b3fba.png)

##問4.6（指数関数・対数関数）

#####1.

```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

x = [-3, -2, -1, 0, 1, 2, 3]

for i in x:
    print('df({})dx = {}'.format(i,dfdx_approx(i)))
    print('exp({}) = {}'.format(i, math.exp(i)))
    print()

```
x = 3 ~ 3までの代入を行うため、それらが入ったリストを作ります。
今回は、代入した数字と、その結果どう言った数値になったかを見やすくするため、formatメソッドを利用し、代入した数字iと、df(x)/dxおよびexp(x)を出力しています。

##問4.7（ニューラルネットワーク関数の微分）

#####1.

ReLU(x)は、xと0のうち大きい方である、ということを言っています。すなわち、x > 0 であれば ReLU(x) = x となり, x =< 0　であれば、 ReLU(x) = 0 になります。

```math
\begin{eqnarray}
ReLU ( x )
=
\begin{cases}
x & ( x \gt 0 ) \\
0 & ( x \leqq 0 )
\end{cases}
\end{eqnarray}
```

これを微分するので、

```math
\begin{eqnarray}
ReLU' ( x )
=
\begin{cases}
1 & ( x \gt 0 ) \\
0 & ( x \lt 0 )
\end{cases}
\end{eqnarray}
```

となります。
問題は x = 0 のときです。右から近づいてきたときは ReLU(x) = x　なのでReLU'(0) = 1となるのに対し、左から近づくと ReLU(0) = 0 のため ReLU'(x) = 0となって、 x = 0において微分したときの値が異なります。この場合は、x=0において微分ができない、ということになります。

#####2.

```math
\begin{align}
tanh' ( x )
&=\frac{(e^{x} - e^{-x})'(e^{x} + e^{-x}) - (e^{x} - e^{-x})(e^{x} + e^{-x})'}{(e^{x} + e^{-x})^2} \\ \\
&=\frac{(e^{x} + e^{-x})(e^{x} + e^{-x}) - (e^{x} - e^{-x})(e^{x} - e^{-x})}{(e^{x} + e^{-x})^2} \\ \\
&=\frac{(e^{2x} + 2 + e^{-2x}) - (e^{2x} - 2 + e^{-2x})}{(e^{x} + e^{-x})^2} \\ \\
&=\frac{4}{(e^{x} - e^{-x})^2}

\end{align}
```

#####3.
合成関数の微分を用います。
$ u = 1 + e^{-x} $ とおくと、$ Sigmoid(x) = 1/u $、 $ du/dx = - e^{-x} $

```math
\begin{align}
Sigmoid' ( x )
&=\frac{df(u)}{du}・ \frac{du}{dx}\\ \\
&=-\frac{1}{u^2} ・ (- e^{-x}）\\ \\
&=\frac{e^{-x}}{(1 + e^{-x})^2}\\ \\

\end{align}
```

これは実は、$ f'(x) = (1 - f(x)) ・ f(x) $となっていて、シグモイド関数の特徴です。

#####4.
合成関数の微分を用います。
$ u = 1 + e^{x} $ とおくと、$ Softplus(x) = log(u) $、 $ du/dx = e^{x} $

```math
\begin{align}
Softplus' ( x )
&=\frac{df(u)}{du}・ \frac{du}{dx}\\ \\
&=\frac{1}{u} ・ e^{x}\\ \\
&=\frac{e^{x}}{1 + e^{x}}\\ \\
&=\frac{1}{e^{-x} + 1}\\ \\

\end{align}
```
シグモイド関数になっていますね。ソフトプラス関数は微分するとシグモイド関数になり、ニューラルネットワークの活性化関数の一つとして使われています。

##問4.8（偏微分）

#####1.
絶対値関数は、中の符号によって場合分けをし、絶対値を外す必要があります。

```math
\begin{eqnarray}

|x|
= \begin{cases}
x & ( x \geqq 0 ) \\
-x & ( x \lt 0 )
\end{cases}
\end{eqnarray}
```
したがって、

```math
\begin{eqnarray}
\frac{\partial f(x,y)}{\partial x}
= {|x|}'
= \begin{cases}
1 & ( x \gt 0 ) \\
-1 & ( x \lt 0 )
\end{cases} \\ \\

\frac{\partial f(x,y)}{\partial y}
= {|y|}'
= \begin{cases}
1 & ( y \gt 0 ) \\
-1 & ( y \lt 0 )
\end{cases}

\end{eqnarray}
```
$ x = 0 $ において、右から近づいたときは $ f'(x,y) = 1$ 、左から近づいたときは$ f'(x,y) = -1$ になります。ある点において右側極限と左側極限の値が異なるとき、その関数はその点において微分できません。よって、今回の式では、  $ x = 0 $ で $ x $ について偏微分することはできません。$ y $ の偏微分についても、同じように $ y = 0 $ で微分することができません。

#####2.

```math
\begin{eqnarray}

|x + y|
= \begin{cases}
x + y & ( x + y \geqq 0 ) \\
- x - y & ( x + y \lt 0 )
\end{cases}
\end{eqnarray}
```

ですので、

```math
\begin{eqnarray}
\frac{\partial f(x,y)}{\partial x}

= \begin{cases}
1 & ( x + y \gt 0 ) \\
-1 & ( x + y \lt 0 )
\end{cases} \\ \\

\frac{\partial f(x,y)}{\partial y}
= \begin{cases}
1 & ( x + y \gt 0 ) \\
-1 & ( x + y \lt 0 )
\end{cases}

\end{eqnarray}
```


<br>
以上です。数学あまり自信がないので、間違っていたら教えていただけると幸いです。
問題5, 6は次回。