引き続き、ゼロDの写経を続ける。今回は、学生の頃が懐かしい懐ワード、数値微分。
全然Deepに入れないけれどおっさんの復習。解析的な微分と数値微分が一致するところを確認してみる。
昔と違うのは、PythonとJupyterNotebookで超絶簡単に実験できるし、
こうやってWordPressでLaTeXで記事を書いたりできる点。
まず、微分の基本的な考え方は以下の通り。高校数学の数3の範囲。
\begin{eqnarray}
\frac{df(x)}{fx} = \lim_{h\rightarrow \infty} \frac{f(x+h)-f(x)}{h}
\end{eqnarray}
情報系学科に入って最初の方でEuler法とRunge-Kutta法を教わってコードを
書いたりレポート書いたりする。懐すぎる..。
または、基本情報の試験かなんかで、小さい値と小さい値どうしの計算で発生する問題が現れる。
ゼロDにはこの定義を少し改良した方法が載っている。へぇ。
\begin{eqnarray}
\frac{df(x)}{fx} = \lim_{h\rightarrow \infty} \frac{f(x+h)-f(x-h)}{2h}
\end{eqnarray}
写経なので、がんばって数値微分を書いて動かしてみる。
簡単な2次関数\(f(x)\)。
\begin{eqnarray}
f(x) &=& x^2 – 5x +3 \\
f'(x) &=& 2x – 5
\end{eqnarray}
1 2 3 |
def numerical_diff(f, x): h = 10e-4 return (f(x+h) - f(x-h)) / (2*h) |
\(f(x)\)と、\(x=2.5\)のところの\(f'(x)\)をmatplotlibで書いてみる。懐い…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
import matplotlib.pyplot as plt import numpy as np def f(x): return x**2 - 5*x + 3 x = np.arange(-10, 10, 0.1) y = f(x) dy = numerical_diff(f,x) plt.plot(x, y) x1 = -2.5 dy1 = numerical_diff(f, x1) y1 = f(x1) # y-y1 = dy1(x-x1) -> y = dy1(x-x1) + y1 j = lambda x: dy1 * (x-x1) + y1 plt.plot(x,j(x)) plt.xlabel('x') plt.ylabel('y') plt.grid() plt.show() |
偏微分
2変数以上の関数の数値微分は以下の通り。片方を止める。
数値微分の方法は上記と同じものを使った。
\begin{eqnarray}
\frac{\partial f(x_0,x_1)}{\partial x_0} &=& \lim_{h\rightarrow \infty} \frac{f(x_0 +h,x_1)-f(x_0-h,x_1)}{2h} \\
\frac{\partial f(x_0,x_1)}{\partial x_1} &=& \lim_{h\rightarrow \infty} \frac{f(x_0,x_1+h)-f(x_0,x_1-h)}{2h}
\end{eqnarray}
\((x_0,x_1)=(1,1)\)における\(x_0\)に対する偏微分\(\frac{\partial f(x_0,x_1)}{x_0}\)、\(x_1\)に対する偏微分\(\frac{\partial f(x_0,x_1)}{x_1}\)を求めてみる。
ちゃんと\(\frac{\partial f(x_0,1.0)}{x_0}=2.00..\)、\(\frac{\partial f(1.0,x_1)}{x_1}=2.00..\)になった。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
import matplotlib.pyplot as plt import numpy as np from mpl_toolkits.mplot3d import Axes3D def f(x): return x[0]**2 + x[1]**2 X = np.meshgrid(np.arange(-5., 5., 0.2),np.arange(-5., 5., 0.2)) Z = f(X) fig = plt.figure(figsize=(6, 6)) axes = fig.add_subplot(111, projection='3d') axes.plot_surface(X[0],X[1], Z) f0 = lambda x: x**2 + 1.0**2 f1 = lambda x: 1.0**2 + x**2 df0 = numerical_diff(f0, 1.0) df1 = numerical_diff(f1, 1.0) print(df0) # 2.0000000000000018 print(df1) # 2.0000000000000018 plt.show() |