Pythonで微分計算を自動化!SymPyとNumPyを使った微分の完全ガイド
微分は数学の基本的な概念であり、機械学習の最適化アルゴリズムにおいて重要な役割を果たします。Pythonでは記号微分(SymPy)と数値微分(NumPy/SciPy)の両方を簡単に実行できます。この記事では、Pythonを使った様々な微分計算の手法を実例とともに解説します。
必要なライブラリのインストール
pip install sympy numpy scipy matplotlib
import sympy as sp
import numpy as np
import matplotlib.pyplot as plt
from scipy.misc import derivative
SymPyによる記号微分
基本的な微分
# 変数の定義
x = sp.Symbol('x')
# 関数の定義と微分
f = x**3 + 2*x**2 + x + 1
f_prime = sp.diff(f, x)
print(f"f(x) = {f}")
print(f"f'(x) = {f_prime}")
多変数関数の偏微分
# 多変数関数
x, y = sp.symbols('x y')
f = x**2 + 2*x*y + y**2
# 偏微分
df_dx = sp.diff(f, x)
df_dy = sp.diff(f, y)
print(f"∂f/∂x = {df_dx}")
print(f"∂f/∂y = {df_dy}")
高次微分
# 2階微分
f = sp.sin(x) + sp.cos(x)
f_double_prime = sp.diff(f, x, 2)
print(f"f''(x) = {f_double_prime}")
# n階微分
f_n = sp.diff(f, x, 3) # 3階微分
print(f"f'''(x) = {f_n}")
微分の数値計算
NumPyによる数値微分
def numerical_derivative(func, x, h=1e-7):
"""数値微分(中央差分)"""
return (func(x + h) - func(x - h)) / (2 * h)
# 例:f(x) = x^2の x=3 での微分
def f(x):
return x**2
x_point = 3
derivative_value = numerical_derivative(f, x_point)
print(f"f'(3) ≈ {derivative_value}")
print(f"理論値: {2 * x_point}")
SciPyによる数値微分
# SciPyを使った数値微分
def f(x):
return np.sin(x)
x_point = np.pi/4
derivative_value = derivative(f, x_point, dx=1e-6)
print(f"sin'(π/4) ≈ {derivative_value}")
print(f"理論値: {np.cos(np.pi/4)}")
合成関数の微分(連鎖律)
# 連鎖律の例
x = sp.Symbol('x')
inner = x**2 + 1
outer = sp.sin(inner)
# 手動で連鎖律を適用
chain_rule_manual = sp.cos(inner) * sp.diff(inner, x)
print(f"手動での連鎖律: {chain_rule_manual}")
# 自動微分
chain_rule_auto = sp.diff(outer, x)
print(f"自動微分: {chain_rule_auto}")
陰関数の微分
# 陰関数微分
x, y = sp.symbols('x y')
equation = x**2 + y**2 - 25 # 円の方程式
# dy/dx を求める
dy_dx = sp.solve(sp.diff(equation, x) + sp.diff(equation, y) * sp.symbols('dydx'), sp.symbols('dydx'))[0]
print(f"dy/dx = {dy_dx}")
微分方程式の解法
1階微分方程式
# dy/dx = 2x の解
x = sp.Symbol('x')
y = sp.Function('y')
# 微分方程式の定義
eq = sp.Eq(y(x).diff(x), 2*x)
# 一般解
general_solution = sp.dsolve(eq, y(x))
print(f"一般解: {general_solution}")
2階微分方程式
# d²y/dx² + y = 0 (調和振動子)
eq2 = sp.Eq(y(x).diff(x, 2) + y(x), 0)
solution = sp.dsolve(eq2, y(x))
print(f"調和振動子の解: {solution}")
勾配とヘシアン行列
勾配ベクトル
# 多変数関数の勾配
x, y, z = sp.symbols('x y z')
f = x**2 + y**2 + z**2
# 勾配ベクトル
gradient = [sp.diff(f, var) for var in [x, y, z]]
print(f"勾配: {gradient}")
ヘシアン行列
def hessian_matrix(expr, variables):
"""ヘシアン行列を計算"""
n = len(variables)
hessian = sp.zeros(n, n)
for i in range(n):
for j in range(n):
hessian[i, j] = sp.diff(expr, variables[i], variables[j])
return hessian
# 例:f(x,y) = x²y + xy² のヘシアン行列
x, y = sp.symbols('x y')
f = x**2 * y + x * y**2
hessian = hessian_matrix(f, [x, y])
print("ヘシアン行列:")
print(hessian)
最適化問題への応用
勾配降下法の実装
def gradient_descent(func, grad_func, x0, learning_rate=0.01, max_iter=1000):
"""勾配降下法"""
x = x0
for i in range(max_iter):
grad = grad_func(x)
x = x - learning_rate * grad
if abs(grad) < 1e-6: # 収束判定
break
return x, i+1
# 例:f(x) = (x-2)² の最小値を求める
def f(x):
return (x - 2)**2
def grad_f(x):
return 2 * (x - 2)
optimal_x, iterations = gradient_descent(f, grad_f, x0=10)
print(f"最適解: x = {optimal_x:.6f}")
print(f"収束までの反復回数: {iterations}")
機械学習での微分の活用
ロジスティック回帰の勾配
def sigmoid(z):
return 1 / (1 + np.exp(-z))
def logistic_gradient(X, y, theta):
"""ロジスティック回帰のコスト関数の勾配"""
m = len(y)
h = sigmoid(X @ theta)
gradient = (1/m) * X.T @ (h - y)
return gradient
# サンプルデータ
X = np.array([[1, 2], [1, 3], [1, 4]]) # バイアス項を含む
y = np.array([0, 1, 1])
theta = np.array([0.1, 0.2])
grad = logistic_gradient(X, y, theta)
print(f"勾配: {grad}")
可視化による微分の理解
# 関数とその微分をプロット
x_vals = np.linspace(-2, 2, 100)
# 関数 f(x) = x³ - 2x² + x + 1
f_vals = x_vals**3 - 2*x_vals**2 + x_vals + 1
f_prime_vals = 3*x_vals**2 - 4*x_vals + 1 # 微分
plt.figure(figsize=(10, 6))
plt.subplot(1, 2, 1)
plt.plot(x_vals, f_vals, 'b-', label='f(x)')
plt.title('原関数')
plt.legend()
plt.grid(True)
plt.subplot(1, 2, 2)
plt.plot(x_vals, f_prime_vals, 'r-', label="f'(x)")
plt.title('微分')
plt.legend()
plt.grid(True)
plt.tight_layout()
plt.show()
自動微分(Automatic Differentiation)
# PyTorchライクな自動微分の概念例
class Variable:
def __init__(self, value, grad=0.0):
self.value = value
self.grad = grad
def __add__(self, other):
result = Variable(self.value + other.value)
# 逆伝播での勾配計算
def backward():
self.grad += result.grad
other.grad += result.grad
result.backward = backward
return result
def __mul__(self, other):
result = Variable(self.value * other.value)
def backward():
self.grad += other.value * result.grad
other.grad += self.value * result.grad
result.backward = backward
return result
# 使用例
x = Variable(3.0)
y = Variable(4.0)
z = x * y + x # z = xy + x
z.grad = 1.0 # dz/dz = 1
z.backward() # 逆伝播
print(f"dz/dx = {x.grad}, dz/dy = {y.grad}")
まとめ
Pythonでの微分計算は、SymPyによる記号微分とNumPy/SciPyによる数値微分の2つのアプローチがあります。記号微分は正確な解析解を得られ、数値微分は複雑な関数でも近似的に計算できます。
これらの技術は機械学習の最適化アルゴリズム、物理シミュレーション、工学計算など様々な分野で活用されています。微分の概念を理解し、Pythonで実装できるようになることで、より高度な数値計算やアルゴリズムの開発が可能になります。
■プロンプトだけでオリジナルアプリを開発・公開してみた!!
■AI時代の第一歩!「AI駆動開発コース」はじめました!
テックジム東京本校で先行開始。
■テックジム東京本校
「武田塾」のプログラミング版といえば「テックジム」。
講義動画なし、教科書なし。「進捗管理とコーチング」で効率学習。
より早く、より安く、しかも対面型のプログラミングスクールです。
<短期講習>5日で5万円の「Pythonミニキャンプ」開催中。
<月1開催>放送作家による映像ディレクター養成講座
<オンライン無料>ゼロから始めるPython爆速講座