1変数関数の微分は「関数の変化率」を求める操作でした。では、$f(x, y)$ のように変数が2つ以上ある関数ではどうでしょうか。偏微分は、多変数関数において「1つの変数だけを変化させたときの変化率」を求める操作です。
偏微分は多変数解析の出発点であり、物理学・工学のあらゆる分野で登場します。電磁気学のマクスウェル方程式、流体力学のナビエ・ストークス方程式、熱伝導方程式など、自然法則の多くは偏微分で記述されます。
本記事の内容
- 偏微分の定義
- 幾何学的意味(接平面の傾き)
- 高階偏微分
- 偏微分の順序交換(シュワルツの定理)
- 具体的な計算例
- Pythonでの可視化
前提知識
偏微分の定義
2変数関数 $f(x, y)$ の $x$ に関する偏微分は、$y$ を定数として固定し、$x$ だけを変化させたときの変化率として定義されます:
$$ \boxed{\frac{\partial f}{\partial x}(x_0, y_0) = \lim_{h \to 0}\frac{f(x_0 + h, y_0) – f(x_0, y_0)}{h}} $$
同様に $y$ に関する偏微分は:
$$ \boxed{\frac{\partial f}{\partial y}(x_0, y_0) = \lim_{h \to 0}\frac{f(x_0, y_0 + h) – f(x_0, y_0)}{h}} $$
偏微分の記号には以下のものが使われます:
$$ \frac{\partial f}{\partial x} = f_x = \partial_x f = D_x f $$
「$\partial$」はラウンドディー(round d)と読みます。通常の微分記号 $d$ と区別するために使います。
偏微分の計算方法
偏微分の計算は、他の変数を定数と見なして、注目する変数で通常の微分を行うだけです。
例1: $f(x, y) = x^2 y + 3xy^2 + 5y$
$x$ で偏微分($y$ は定数):
$$ \frac{\partial f}{\partial x} = 2xy + 3y^2 $$
$y$ で偏微分($x$ は定数):
$$ \frac{\partial f}{\partial y} = x^2 + 6xy + 5 $$
例2: $f(x, y) = e^{x^2 + y^2}$
$$ \frac{\partial f}{\partial x} = 2x \cdot e^{x^2 + y^2} $$
$$ \frac{\partial f}{\partial y} = 2y \cdot e^{x^2 + y^2} $$
例3: $f(x, y) = \sin(xy)$
$$ \frac{\partial f}{\partial x} = y\cos(xy) $$
$$ \frac{\partial f}{\partial y} = x\cos(xy) $$
幾何学的意味:接平面の傾き
2変数関数 $z = f(x, y)$ は3次元空間で曲面を表します。点 $(x_0, y_0, f(x_0, y_0))$ における偏微分の幾何学的意味を考えましょう。
$\partial f / \partial x$ は、$y = y_0$ で固定した断面曲線 $z = f(x, y_0)$ の傾きです。つまり、$x$ 方向に曲面を「切った」ときの断面の勾配を表します。
同様に、$\partial f / \partial y$ は $x = x_0$ で固定した断面曲線 $z = f(x_0, y)$ の傾きです。
これら2つの偏微分から、点 $(x_0, y_0)$ における接平面の方程式が得られます:
$$ \boxed{z = f(x_0, y_0) + \frac{\partial f}{\partial x}(x_0, y_0)(x – x_0) + \frac{\partial f}{\partial y}(x_0, y_0)(y – y_0)} $$
接平面は曲面を局所的に平面で近似したものであり、偏微分は接平面の「傾き」を決定するパラメータです。
高階偏微分
偏微分の結果もまた $x, y$ の関数なので、さらに偏微分できます。
2階偏微分
$f(x, y)$ の2階偏微分には4通りがあります:
$$ \frac{\partial^2 f}{\partial x^2} = f_{xx}, \quad \frac{\partial^2 f}{\partial y^2} = f_{yy} $$
$$ \frac{\partial^2 f}{\partial y \partial x} = f_{xy}, \quad \frac{\partial^2 f}{\partial x \partial y} = f_{yx} $$
注意すべきは、$\frac{\partial^2 f}{\partial y \partial x}$ は「まず $x$ で偏微分し、次に $y$ で偏微分する」という意味です。記号の読み方は右から左です:
$$ \frac{\partial^2 f}{\partial y \partial x} = \frac{\partial}{\partial y}\left(\frac{\partial f}{\partial x}\right) $$
具体例
$f(x, y) = x^3 y^2 + x \sin y$ の2階偏微分をすべて計算します。
まず1階偏微分:
$$ f_x = 3x^2 y^2 + \sin y $$
$$ f_y = 2x^3 y + x\cos y $$
次に2階偏微分:
$$ f_{xx} = \frac{\partial}{\partial x}(3x^2 y^2 + \sin y) = 6xy^2 $$
$$ f_{yy} = \frac{\partial}{\partial y}(2x^3 y + x\cos y) = 2x^3 – x\sin y $$
$$ f_{xy} = \frac{\partial}{\partial y}(3x^2 y^2 + \sin y) = 6x^2 y + \cos y $$
$$ f_{yx} = \frac{\partial}{\partial x}(2x^3 y + x\cos y) = 6x^2 y + \cos y $$
$f_{xy} = f_{yx}$ が成り立っていることを確認できます。
シュワルツの定理(偏微分の順序交換)
上の例で $f_{xy} = f_{yx}$ が成立しましたが、これは偶然ではありません。
シュワルツの定理(クレローの定理): $f(x, y)$ の2階偏微分 $f_{xy}$ と $f_{yx}$ がともに存在し、かつともに連続であれば:
$$ \boxed{\frac{\partial^2 f}{\partial x \partial y} = \frac{\partial^2 f}{\partial y \partial x}} $$
すなわち、偏微分の順序を入れ替えても結果は同じです。
物理学や工学で扱うほとんどの関数は十分に滑らかであるため、実用上はほぼ常に偏微分の順序交換が可能です。
シュワルツの定理が成り立たない例(参考)
条件を満たさない例として、以下の関数は $(0, 0)$ で $f_{xy} \neq f_{yx}$ となります:
$$ f(x, y) = \begin{cases} \dfrac{xy(x^2 – y^2)}{x^2 + y^2} & (x, y) \neq (0, 0) \\ 0 & (x, y) = (0, 0) \end{cases} $$
この関数では $f_{xy}(0,0) = 1$、$f_{yx}(0,0) = -1$ です。これは $f_{xy}$ と $f_{yx}$ が原点で連続でないためです。
$n$ 変数関数への一般化
$n$ 変数関数 $f(x_1, x_2, \dots, x_n)$ の $x_k$ に関する偏微分は:
$$ \frac{\partial f}{\partial x_k} = \lim_{h \to 0}\frac{f(x_1, \dots, x_k + h, \dots, x_n) – f(x_1, \dots, x_k, \dots, x_n)}{h} $$
各変数について偏微分したベクトルを勾配(gradient)と呼びます:
$$ \nabla f = \left(\frac{\partial f}{\partial x_1}, \frac{\partial f}{\partial x_2}, \dots, \frac{\partial f}{\partial x_n}\right) $$
勾配ベクトルは、関数値が最も急激に増加する方向を指し、その大きさは増加率を表します。
Pythonでの可視化
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
# ============================
# 偏微分の幾何学的意味の可視化
# ============================
# f(x, y) = x^2 + y^2 を例にする
def f(x, y):
return x**2 + y**2
def f_x(x, y):
return 2*x
def f_y(x, y):
return 2*y
x = np.linspace(-2, 2, 100)
y = np.linspace(-2, 2, 100)
X, Y = np.meshgrid(x, y)
Z = f(X, Y)
fig = plt.figure(figsize=(18, 6))
# === (1) 曲面と接平面 ===
ax1 = fig.add_subplot(131, projection='3d')
# 曲面
ax1.plot_surface(X, Y, Z, alpha=0.4, cmap='coolwarm')
# 接点
x0, y0 = 1.0, 0.5
z0 = f(x0, y0)
ax1.scatter([x0], [y0], [z0], color='red', s=100, zorder=5)
# 接平面
x_tp = np.linspace(x0-1, x0+1, 20)
y_tp = np.linspace(y0-1, y0+1, 20)
X_tp, Y_tp = np.meshgrid(x_tp, y_tp)
Z_tp = z0 + f_x(x0, y0)*(X_tp - x0) + f_y(x0, y0)*(Y_tp - y0)
ax1.plot_surface(X_tp, Y_tp, Z_tp, alpha=0.5, color='orange')
# x方向の断面曲線
y_fixed = y0 * np.ones_like(x)
z_sec_x = f(x, y_fixed)
ax1.plot(x, y_fixed, z_sec_x, 'b-', lw=2, label='$y = y_0$ section')
ax1.set_xlabel('$x$'); ax1.set_ylabel('$y$'); ax1.set_zlabel('$z$')
ax1.set_title('Surface, tangent plane\nand cross sections', fontsize=12)
ax1.view_init(elev=25, azim=-60)
# === (2) x方向の偏微分 ===
ax2 = fig.add_subplot(132)
z_section = f(x, y0)
ax2.plot(x, z_section, 'b-', lw=2, label=f'$f(x, {y0})$')
# 接線
slope_x = f_x(x0, y0)
tangent_x = z0 + slope_x * (x - x0)
ax2.plot(x, tangent_x, 'r--', lw=2,
label=f'Tangent (slope = $f_x$ = {slope_x:.1f})')
ax2.plot(x0, z0, 'ro', ms=8)
ax2.set_xlabel('$x$', fontsize=12)
ax2.set_ylabel('$z$', fontsize=12)
ax2.set_title(f'Cross section at $y = {y0}$\n'
f'$\\partial f/\\partial x = {slope_x:.1f}$', fontsize=12)
ax2.legend(fontsize=10)
ax2.grid(True, alpha=0.3)
ax2.set_xlim(-2, 2)
# === (3) 勾配ベクトル場 ===
ax3 = fig.add_subplot(133)
x_q = np.linspace(-2, 2, 15)
y_q = np.linspace(-2, 2, 15)
X_q, Y_q = np.meshgrid(x_q, y_q)
U = f_x(X_q, Y_q)
V = f_y(X_q, Y_q)
# 等高線
cs = ax3.contour(X, Y, Z, levels=15, cmap='coolwarm', alpha=0.7)
ax3.clabel(cs, fontsize=8)
# 勾配ベクトル場
ax3.quiver(X_q, Y_q, U, V, color='black', alpha=0.7,
scale=50, width=0.003)
ax3.set_xlabel('$x$', fontsize=12)
ax3.set_ylabel('$y$', fontsize=12)
ax3.set_title('Gradient field $\\nabla f$\nwith contours', fontsize=12)
ax3.set_aspect('equal')
ax3.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig('partial_derivative.png', dpi=150, bbox_inches='tight')
plt.show()
# === (4) シュワルツの定理の数値検証 ===
fig2, axes2 = plt.subplots(1, 2, figsize=(14, 6))
# f(x, y) = x^3 * y^2 + x * sin(y)
def g(x, y):
return x**3 * y**2 + x * np.sin(y)
h = 1e-5
x_grid = np.linspace(-2, 2, 100)
y_grid = np.linspace(-2, 2, 100)
Xg, Yg = np.meshgrid(x_grid, y_grid)
# 数値的に f_xy を計算(まずxで微分、次にyで微分)
g_x = (g(Xg+h, Yg) - g(Xg-h, Yg)) / (2*h)
g_xy_num = np.zeros_like(Xg)
for i in range(len(y_grid)):
for j in range(len(x_grid)):
g_xy_num[i,j] = (
(g(x_grid[j]+h, y_grid[i]+h) - g(x_grid[j]-h, y_grid[i]+h)
- g(x_grid[j]+h, y_grid[i]-h) + g(x_grid[j]-h, y_grid[i]-h))
/ (4*h**2)
)
# 解析的に f_xy と f_yx
g_xy_exact = 6*Xg**2 * Yg + np.cos(Yg) # = f_yx_exact
cs1 = axes2[0].contourf(Xg, Yg, g_xy_exact, levels=20, cmap='viridis')
plt.colorbar(cs1, ax=axes2[0])
axes2[0].set_xlabel('$x$'); axes2[0].set_ylabel('$y$')
axes2[0].set_title('$f_{xy}$ (analytical)', fontsize=12)
cs2 = axes2[1].contourf(Xg, Yg, g_xy_num, levels=20, cmap='viridis')
plt.colorbar(cs2, ax=axes2[1])
axes2[1].set_xlabel('$x$'); axes2[1].set_ylabel('$y$')
axes2[1].set_title('$f_{xy}$ (numerical)', fontsize=12)
plt.suptitle("Schwarz's theorem: $f_{xy} = f_{yx}$", fontsize=14, y=1.02)
plt.tight_layout()
plt.savefig('schwarz_theorem.png', dpi=150, bbox_inches='tight')
plt.show()
上段の左の図は、放物面 $z = x^2 + y^2$ と接平面(オレンジ)を3次元で示しています。中央の図は $y = 0.5$ における断面曲線と接線を描いており、接線の傾きがまさに $\partial f/\partial x$ であることがわかります。右の図は勾配ベクトル場 $\nabla f$ と等高線を重ねたもので、勾配ベクトルが等高線に常に直交している様子が確認できます。
下段の図は、関数 $f(x,y) = x^3 y^2 + x\sin y$ に対して $f_{xy}$ を解析的に計算した結果と数値微分した結果を比較しており、シュワルツの定理が数値的にも成り立つことを確認しています。
まとめ
本記事では、偏微分の定義と計算方法について解説しました。
- 偏微分は他の変数を固定して1変数だけで微分する操作
- 幾何学的には曲面の断面曲線の傾きを表し、接平面を決定する
- 高階偏微分は偏微分を繰り返す操作で、2階では4種類ある
- シュワルツの定理: 2階偏微分が連続なら $f_{xy} = f_{yx}$(順序交換可能)
- 勾配 $\nabla f$ は偏微分をまとめたベクトルで、最急上昇方向を指す
次のステップとして、以下の記事も参考にしてください。