こんにちは。オルトプラスラボに入って2週間と4日の橘です。
今回は前回に引き続き、2章を読んでいきます。
2章は機械学習の基礎中の基礎である2乗誤差についてです。
基礎とは言え、微分や行列が出てくるため、その辺をじっくり見ていきたいと思います。
多項式近似と誤差関数の設定
多項式近似とは何か、を見ていく前に、多項式近似のイメージを次の画像で見てみましょう。
多項式近似とは、「適当な線を引き、学習させたい点(データ)に近づくように線を曲げる」ようなイメージです。まず、これを頭のなかに入れておいてください。
それでは数学的な説明に移ります。多項式とは、
を言います。上の図でいうところの青い線が多項式です。つまり、この多項式を色々動かしてデータを分析したり予測したりしていくわけです。
ちなみに、予測したい各点を と表します。例えば、
地点の
との差は次のように見ることができます。
この差を縮めるように、線である多項式を調整していきます。この時、多項式の中のはデータの値のため、変更できません。そのため、変更できるパラメータは
です。つまり、機械学習で求めていく値はこの
ということになります。このことはとても重要なため、よく覚えておいてください。
各データの点と線の差が次の式です。2乗誤差といいます。
なぜ しているのかというと、後々の計算を楽にするためです。
しても誤差が0になるわけではないので、多めに見てください。各データと線の差である
を2乗しているのは、すべての差を正の値にするためです。なぜ正の値にする必要があるかというと、例えば3つの点の誤差を見たときに(-0.5, 1, -0.5)だったとき、誤差を足してしまうと0になってしまい、正確にデータを予測しているように見えてしまいます。こうなることを防ぐために、すべての差を2乗しているわけです。この誤差が小さくなるように、
の値を求めていきます。
ここからがP64の数学徒の小部屋の解説に入ります。ここで微分が登場します。なぜ微分が登場するかは、たまたま偶然ミラクルに同じ苗字の橘氏がデータホテル様のテックブログで解説してくれているので、そちらをご参照ください。いやー、偶然ってあるんだなー。
要するに、「ある地点で微分した結果が0のとき、その地点で最大値か最小値になる」という性質があります。これを、各について求めていくわけです。
の中のある
で微分したときに0になると仮定します。(あえて本の中での
と
とが逆にしています。)
一見複雑に見えますがは足し算ですので、順番を変更する事ができます。本の中でも「作為的」と書いてありますが、この計算を行列で表現するための工夫です。
この式はについて微分した結果ですが、各mについて微分した結果を行列の形に表したものが、次の式です。
各行列は本の65ページのとおりです。なぜ、こうなるか困惑した方も多いのではないかと思います。ですので、N=2、M=2のときで計算を試してみました。行列の演算の仕方はデータホテル様のテックブログを御覧ください。
行列の中の式が
と同じになっています。行列の各行がについて微分した式と一致していることがわかるかと思います。これをmが0からMのときまで実行しても同じ結果が得られます。この
はwについての方程式ですので、w に関して求めると次のような結果になります。
は
からなる行列ですので、既にわかっているデータです。また、
も各
からなるベクトルですので、既にわかっているデータです。つまり、この行列の計算をしてしまえば、最も適切な
が求められます。
(行列の正定値性、ヘッセ行列に関しては次回解説します。)
サンプルコード
Numpyのnp.polyfitメソッドを使うことで、簡単に多項式近似できます。
import numpy as np import matplotlib.pyplot as plt import pandas as pd from pandas import Series, DataFrame from numpy.random import normal # データセットを用意 def create_dataset(num): dataset = DataFrame(columns=["x", "y"]) for i in range(num): x = float(i)/float(num-1) # 平均0.0、分散0.3の正規分布を誤差として与えている y = np.sin(2 * np.pi * x) + normal(scale=0.3) dataset = dataset.append(Series([x, y], index=["x", "y"]), ignore_index=True) return dataset if __name__ == "__main__": // データセットを作る df = create_dataset(10) X = df.x.values y = df.y.values x = np.arange(0, 1.1, 0.01) // データセットをプロットする plt.scatter(X, y) // 近似した線を引く plt.plot(x, np.poly1d(np.polyfit(X, y, 4))(x), color="r") plt.show()
実行結果は以下のとおりです。
次回
次回は第2章の後半と今回紹介できなかった正定値性、ヘッセ行列に関して解説します。