##背景
データサイエンスを始めるにあたり、Chainer Tutorialをやりました。
初学者にもわかりやすい文章で、数学やpythonの基本から教えてくれるので、機械学習の入門にはおすすめだと思います(しかも無料!)。
準備編の最後に演習問題がついていますが、復習がてら解答をまとめ、投稿しようと思った次第です。
Chainerチュートリアル Step1演習問題の解答1(本記事) → 問題2, 4
Chainerチュートリアル Step1演習問題の解答2 → 問題5, 6
##問2.1(組み込み関数)
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(リストの基本操作)
#リスト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つを削除します。
#リストaの末尾に 100 という値を追加して、[4, 8, 3, 4, 1, 100] となるようにして下さい。
a = [4, 8, 3, 4, 1]
a.append(100)
print(a)
appendメソッドは末尾に引数の値を追加します。
ちなみに、先頭に追加したい時はinsertメソッドを用いて、第一引数に追加したい場所、第二引数に追加したい要素を指定します。
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] に変換されるべきです。
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に含まれる奇数の個数と等しくなるはずです。
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 から奇数の要素だけを残すコードを書いて下さい。
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メソッドは、文字列に対する組み込み関数です。引数に配列を与えることで、配列内の要素を文字列で区切った、一つの文字列を形成します。
a = [str(x) for x in range(100)] #[0,1,2, ・・・, 98, 99]という配列を作る
str = ' '.join(a) #半角スペースに対してjoinを使うことで、配列要素をスペースで区切った1つの文字列を作る
print(str)
#####2. str.format() を使って float の値 (1.0 / 7.0) の小数点以下9桁までを表示して下さい。
formatメソッドは、文字列内の{ }で囲まれたエリアに対し、引数で受けた値を埋め込みます。
{インデックス番号:書式設定}としてかき、インデックス番号は位置を、書式設定は桁数などを指定できます。
インデックス番号は省略できます。
sentence = "{0}は{1}です".format("クジラ", "哺乳類")
print(sentence)
>>クジラは哺乳類です
小数点を指定する時は、{: .数字f}とします。
num = 1.0/7.0
print('{0:.9f}'.format(num)) #インデックス番号を省略し、print('{:.9f}'.format(num))でもok
##問2.6(クラス)
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(制御構文)
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.2(線形性)
##問4.4(合成関数の微分)
##問4.5(合成関数の微分)
#####1.𝑔(𝑥)=𝑥^4+2^𝑥2+2 となることを確認して下さい。また、これより 𝑔′(𝑥)=4𝑥3+4𝑥 となることを確認して下さい。
#####2.一方で、合成関数の微分則によって 𝑔′(𝑥) を計算し、(1) で求めた導関数と一致することを確認して下さい。
1.で求めた式と一致しています。
#####3.ℎ(𝑥)=𝑓(𝑓(𝑓(𝑥))) とします。合成関数の微分によって ℎ′(𝑥) を計算して下さい。
##問4.6(指数関数・対数関数)
#####1.
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 になります。
\begin{eqnarray}
ReLU ( x )
=
\begin{cases}
x & ( x \gt 0 ) \\
0 & ( x \leqq 0 )
\end{cases}
\end{eqnarray}
これを微分するので、
\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.
\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} $
\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} $
\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.
絶対値関数は、中の符号によって場合分けをし、絶対値を外す必要があります。
\begin{eqnarray}
|x|
= \begin{cases}
x & ( x \geqq 0 ) \\
-x & ( x \lt 0 )
\end{cases}
\end{eqnarray}
したがって、
\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.
\begin{eqnarray}
|x + y|
= \begin{cases}
x + y & ( x + y \geqq 0 ) \\
- x - y & ( x + y \lt 0 )
\end{cases}
\end{eqnarray}
ですので、
\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}
以上です。数学あまり自信がないので、間違っていたら教えていただけると幸いです。 問題5, 6は次回。