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爆速講座