機械学習の理論や論文を勉強していると、時々テイラー展開 (Taylor Expansion)やマクローリン展開(Maclaurin Expansion)に遭遇します。
正直テイラー展開なんて知らないよ … と思う人も多いと思いますが、実際私も大学1年生の時に学んで以来さっぱりで、実務で触れるにあたって学び直しています。
しかし非常に登場頻度も高く、勉強する価値は高いのでテイラー展開とマクローリン展開について学んでいきましょう。
非常に登場頻度も高く、これらを学ぶことは非常に重要です。
テイラー展開の概要
まず、テイラー展開がどのようなものかについて理解しましょう。
テイラー展開は、任意の関数$f(x)$を多項式を用いて表現しようとするものです。
証明は少し手間がかかるので、結論だけでもおさえておくと良いでしょう。
無限回微分可能な関数$f(x)$が、 次のように表現できる時、
\begin{equation} \begin{split} f(x) &= f(a) + f'(a)(x-a) + \frac{f''(a)}{2!}(x-a)^2 + \dots + \frac{f^{(n)}(a)}{n!} (x-a)^n + \dots \\ &= \sum_{n=0}^{\infin} \frac{f^{(n)}(a)}{n!}(x-a)^n \end{split} \end{equation}
(1)式を、$x=a$におけるテイラー展開という。
テイラー展開は、次のように定義されます。
一方、$x=0$におけるテイラー展開をマクローリン展開と言います。
$x=0$近傍で、関数$f(x)$が無限回微分可能な関数の時、
\begin{equation} \begin{split} f(x) & = f(0) + f'(0)(x) + \frac{f''(0)}{2!}(x)^2 + \dots + \frac{f^{(n)}(0)}{n!} (x)^n + \dots \\ &= \sum_{n=0}^{\infin} \frac{f^{(n)}(0)}{n!}(x)^n \end{split} \end{equation}
(2)式を、マクローリン展開と呼ぶ。
実用上よく登場するマクローリン展開
(2)式を利用することで、$x=0$近傍で無限回微分可能な関数は、一般的に表現できることがわかります。
一方で、特に次の関数におけるマクローリン展開は非常に多く登場するので、いつでも思い出せるようにしておくと良いでしょう。
e^x = 1 + \frac{1}{1!}x + \frac{1}{2!}x^2 + \dots + \frac{1}{n!}x^n + \dots
log(1+x) = \frac{1}{x} - \frac{1}{x^2} + \frac{1}{x^3} - \dots + (-1)^{n+1} \frac{x^n}{n} + \dots
sinx = x - \frac{x^3}{3!} + \frac{x^5}{5!} - \frac{x^7}{7!} \dots + (-1)^{n}\frac{x^{2n+1}}{(2n+1)!} + \dots
cosx = 1 - \frac{x^2}{2!} + \frac{x^4}{4!} - \frac{x^6}{6!} + \dots + (-1)^n\frac{x^{2n}}{2n!} + \dots
機械学習におけるテイラー展開・マクローリン展開
機械学習分野では、テイラー展開やマクローリン展開は比較的よく登場します。
特に、損失関数などの関数を最小化するための勾配を探索する際に、テイラー展開が利用されたりします。
テイラー展開を実際に実装して確かめる
テイラー展開やマクローリン展開の数式を、具体例を通してみていきましょう。
テイラー展開は一般的な形ですが、マクローリン展開の方が数式が簡単なので、今回はマクローリン展開を扱ってみます。
今回題材として、関数$sinx$をマクローリン展開を考えてみます。
$sin(x)$のマクローリン展開
$sin(x)$のグラフをまずは書いてみましょう。
import numpy as np
import math
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(10, 3), dpi=120)
x = np.linspace(-20, 20, 1000)
y = np.sin(x)
ax.plot(x, y)
sin(x)の関数はこのようになっています。
ここで、$sinx$のマクローリン展開は次のようになるのでした。
sinx = x - \frac{x^3}{3!} + \frac{x^5}{5!} - \frac{x^7}{7!} \dots + (-1)^{n}\frac{x^{2n+1}}{(2n+1)!} + \dots
まず、$sinx$の3次のマクローリン展開はこのようになっています。
sinx = x - \frac{x^3}{3!}
これを描写してみましょう。コードは次のようになります。
fig, ax = plt.subplots(figsize=(10, 3), dpi=120)
ax.set_ylim([-2, 2])
x = np.linspace(-10, 10, 1000)
y = np.sin(x)
y_maclaurin3 = x - pow(x, 3) / 3 * 2 * 1
ax.plot(x, y, label="y = sin(x)")
ax.plot(x, y_maclaurin3, label=r"$y = x - \frac{x^3}{3!}$")
ax.legend()
$x=0$近傍ではいい感じに近似できていますが、それ以外では当てはまっていないことがわかります。
では、マクローリン展開の次数$n$を増やしてみます。次数$n$に対する$sin(x)$のマクローリン展開を実装した関数を次のように実装し、可視化します。
def sin_maclaurin(x, n):
t = np.zeros(len(x))
for i in range(n):
deg = i + 1
if deg % 2 != 0:
t += (-1) ** ((deg - 1) // 2) * (pow(x, deg) / math.factorial(deg))
return t
次数を1から17まで変化させて、グラフ化してみます。
fig, ax = plt.subplots(figsize=(10, 4), dpi=120)
ax.set_ylim([-2, 2])
x = np.linspace(-10, 10, 200)
y = np.sin(x)
sin_mac_3 = sin_maclaurin(x, 11)
dims = [i for i in range(0, 18) if i%2 != 0 ]
ax.plot(x, y, label="sin(x)")
for idx, dim in enumerate(dims):
data = sin_maclaurin(x, dim)
ax.plot(x, data, label="dim={}".format(dim))
ax.legend()
結果はこのようになりました。多すぎてみにくいですが、水色の線が$n=17$でマクローリン展開したもので、ある程度の範囲まではよく近似できていることがわかります。
このように、$sin(x)$の場合は、マクローリン展開の次数を増やすことで、より広い範囲で関数を近似できることがわかりました。