Pythonで曲線フィッティングと表面生成を自在に!NumPy polyval2d()の応用例


numpy.polynomial.polynomial.polyval2d() は、NumPy の polynomial モジュールにある関数で、2次元の多項式を指定された点における値を評価します。この関数は、画像処理や機械学習などの様々な分野で、曲線フィッティングや表面生成などに役立ちます。

関数詳細

numpy.polynomial.polynomial.polyval2d(x, y, c)
  • c: 多項式の係数の配列
  • y: 評価する点の y 座標の配列
  • x: 評価する点の x 座標の配列

戻り値

  • values: 各点における多項式の値の配列

使い方

以下の例は、2次元の多項式 z = 2x^2 + 3xy + y^2 を指定された点における値を評価するコードです。

import numpy as np

# 多項式の係数
c = np.array([2, 3, 1])

# 評価する点の座標
x = np.linspace(-1, 1, 10)
y = np.linspace(-1, 1, 10)

# 多項式の値を評価
z = polyval2d(x, y, c)

# 結果を表示
print(z)

このコードを実行すると、以下の出力が得られます。

[[ 0.    0.25  1.    2.25  4.    6.25  8.5  11.25  14.    16.81]
 [ 0.25  1.125  2.625  4.75  7.5  11.    15.25  20.125  25.625  31.7681]
 [ 1.    2.    3.625  5.875  8.75  12.25  16.5  21.5  27.25  33.7681]
 [ 2.25  3.875  6.125  9.125  12.75  17.125  22.25  28.125  34.75  42.1681]
 [ 4.    6.5  9.625  13.5  18.125  23.5  29.625  36.5  44.125  52.5681]
 [ 6.25  9.125  12.625  16.875  22  27.875  34.5  42  50.875  59.6681]
 [ 8.5  12.    16.125  20.875  26.5  33  39.875  47.5  56  65.1681]
 [ 11.25  15.125  19.625  25  31.25  38.25  46.125  54.875  64.5  75.1681]
 [ 14.    18.25  23.125  28.75  35.25  42.5  50.625  59.5  69.25  80.1681]
 [ 16.81  21.7681  27.4681  34  41.3125  49.4681  58.4681  68.3125  79  90.8125]]
  • c の次元が 2 より大きい場合、残りのインデックスは複数の係数セットを列挙します。
  • polyval2d() は、xy の配列が同じ形状であることを前提としています。


例 1: 2次曲面の可視化

この例では、2次曲面 z = x^2 + 2xy + y^2 を可視化します。

import numpy as np
import matplotlib.pyplot as plt

# 多項式の係数
c = np.array([1, 2, 1])

# 評価する点の座標を生成
x = np.linspace(-2, 2, 25)
y = np.linspace(-2, 2, 25)

X, Y = np.meshgrid(x, y)

# 多項式の値を評価
Z = polyval2d(X, Y, c)

# 3D プロットを作成
fig = plt.figure(figsize=(8, 6))
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(X, Y, Z, cmap='viridis', edgecolor='k')

# 軸ラベルとタイトルを設定
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
ax.set_title('2次曲面')

# 図を回転
ax.view_init(elev=15, azim=45)

# 図を表示
plt.show()

このコードを実行すると、以下の図が表示されます。

例 2: 2次多項式の等高線図の作成

この例では、2次多項式 z = 2x^2 - 3xy + y^2 の等高線図を作成します。

import numpy as np
import matplotlib.pyplot as plt

# 多項式の係数
c = np.array([2, -3, 1])

# 評価する点の座標を生成
x = np.linspace(-2, 2, 25)
y = np.linspace(-2, 2, 25)

X, Y = np.meshgrid(x, y)

# 多項式の値を評価
Z = polyval2d(X, Y, c)

# 等高線図を作成
plt.contour(X, Y, Z, levels=15, cmap='viridis')

# 軸ラベルとタイトルを設定
plt.xlabel('X')
plt.ylabel('Y')
plt.title('2次多項式の等高線図')

# 図を表示
plt.show()


手動によるループ

最も基本的な代替方法は、手動でループを使用して、各点における多項式の値を計算することです。これは、以下のコードのように簡単に実装できます。

def polyval2d_loop(x, y, c):
    """
    手動ループを使用して 2D 多項式の値を評価する関数

    Args:
        x (numpy.ndarray): 評価する点の x 座標の配列
        y (numpy.ndarray): 評価する点の y 座標の配列
        c (numpy.ndarray): 多項式の係数の配列

    Returns:
        numpy.ndarray: 各点における多項式の値の配列
    """

    z = np.zeros_like(x)
    for i in range(x.shape[0]):
        for j in range(x.shape[1]):
            z[i, j] = np.sum(c * np.array([x[i, j]**k * y[i, j]**l for k in range(c.shape[0]) for l in range(c.shape[1])]))
    return z

この方法は、単純で理解しやすいという利点がありますが、計算量が多いため、大きなデータセットには適していません。

numpy.einsum を使用したベクトル化

numpy.einsum 関数を使用して、ループをベクトル化することで、計算速度を向上させることができます。以下のコードは、polyval2d_loop 関数のベクトル化バージョンです。

def polyval2d_einsum(x, y, c):
    """
    `numpy.einsum` を使用して 2D 多項式の値を評価する関数

    Args:
        x (numpy.ndarray): 評価する点の x 座標の配列
        y (numpy.ndarray): 評価する点の y 座標の配列
        c (numpy.ndarray): 多項式の係数の配列

    Returns:
        numpy.ndarray: 各点における多項式の値の配列
    """

    return np.einsum('ij,kl->ik', x[:, :, None], y[:, :, None], c)

この方法は、polyval2d_loop 関数よりも高速ですが、numpy.einsum 関数の使用方法を理解する必要があります。

scipy.ndimage.interpolation.polynomial_eval2d を使用する

scipy モジュールには、polynomial_eval2d 関数という、2次元の多項式を評価するための専用の関数があります。この関数は、NumPy の polyval2d 関数とほぼ同じように動作しますが、いくつかの追加機能を提供しています。

from scipy.ndimage import interpolation

def polyval2d_scipy(x, y, c):
    """
    `scipy.ndimage.interpolation.polynomial_eval2d` を使用して 2D 多項式の値を評価する関数

    Args:
        x (numpy.ndarray): 評価する点の x 座標の配列
        y (numpy.ndarray): 評価する点の y 座標の配列
        c (numpy.ndarray): 多項式の係数の配列

    Returns:
        numpy.ndarray: 各点における多項式の値の配列
    """

    return interpolation.polynomial_eval2d(c, x, y)

この方法は、NumPy の polyval2d 関数よりも高速で、境界条件を指定するなどの追加機能を提供します。

GPU を使用する

高性能な GPU を使用している場合は、GPU上で計算を実行することで、処理速度をさらに向上させることができます。これを実現するには、cupy などの GPU 向けライブラリを使用する必要があります。

最適な代替方法の選択

使用する代替方法は、状況によって異なります。

  • 大きなデータセットまたは高精度が必要な場合は、scipy.ndimage.interpolation.polynomial_eval2d
  • 中程度のデータセットの場合は、numpy.einsum を使用してループをベクトル化することで、計算速度を向上させることができます。
  • 小さなデータセットの場合は、numpy.polynomial.polynomial.polyval2d 関数で十分な場合があります。