単調な校正データを補間しているのに曲線が上下へ行き過ぎるなら、形を保つPchipInterpolatorを検討する。入力xは重複なしの昇順にし、使ってよい範囲を限定するためextrapolate=Falseを指定する。滑らかな線が描けることと、その値を推定に使ってよいことは別である。
最小例で確かめる
以下は説明用に作った小さなデータである。実測データや実行速度の測定結果ではない。コード全体をexample.pyとして保存すれば、入力ファイルを別途用意せずに実行できる。assertは、この例で成り立つべき形や値を確認するために入れてある。
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import PchipInterpolator, CubicSpline
x = np.array([0., 1., 2., 3.])
y = np.array([0., 1., 1., 1.])
assert np.isfinite(x).all() and np.isfinite(y).all()
assert (np.diff(x) > 0).all()
pchip = PchipInterpolator(x, y, extrapolate=False)
cubic = CubicSpline(x, y, extrapolate=False)
grid = np.linspace(x[0], x[-1], 601)
yp = pchip(grid)
yc = cubic(grid)
print("PCHIP range:", np.round([yp.min(), yp.max()], 6).tolist())
print("cubic overshoot:", bool(yc.max() > y.max()))
print("outside:", pchip([-0.5, 3.5]).tolist())
try:
PchipInterpolator([0., 1., 1., 2.], [0., 1., 1., 2.])
except ValueError:
print("expected: ValueError for repeated x")
else:
raise AssertionError("repeated x was accepted")
np.testing.assert_allclose(pchip(x), y, atol=1e-12)
assert (np.diff(yp) >= -1e-12).all()
assert yp.min() >= -1e-12 and yp.max() <= 1 + 1e-12
assert yc.max() > 1.05
assert np.isnan(pchip([-0.5, 3.5])).all()
fig, ax = plt.subplots(figsize=(7, 4), layout="constrained")
ax.plot(grid, yc, "--", color="#e38619", label="CubicSpline (default boundary)")
ax.plot(grid, yp, color="#a83262", linewidth=2, label="PCHIP")
ax.plot(x, y, "o", color="#26778c", label="calibration samples")
ax.axhline(1, color="0.6", linewidth=1)
ax.set(xlabel="Input [arb. unit]", ylabel="Response [arb. unit]",
title="Monotone samples and interpolation overshoot")
ax.legend(loc="lower right")
fig.savefig("PY085-interpolation.png", dpi=160)
plt.close(fig)
実行結果
PCHIP range: [0.0, 1.0]
cubic overshoot: True
outside: [nan, nan]
expected: ValueError for repeated x
点を通るだけでは十分ではない
CubicSplineもPCHIPも標本点を通るが、点と点の間の形は異なる。この例では0から1へ増えたあと一定となる値を使い、標準の境界条件のCubicSplineが1を超えることを確認した。校正曲線などで出力が単調であるべき場合、この行き過ぎが変換値へ影響する。
PCHIPは区分的な3次Hermite補間で、入力データの単調性を保つように傾きを決める。例では範囲内の細かい格子上で、減少せず0から1の範囲にあることを確認している。この検査は作った例の数値確認であり、無条件にすべての実データが単調になるという意味ではない。入力自体が上下すれば、その情報も反映される。
xの順序と重複を先に調べる
PchipInterpolatorのxは1次元で厳密に増加している必要がある。同じxに異なるyがあると、一つの入力値に複数の応答が対応してしまう。例では重複したxがValueErrorになることを確かめた。重複が再測定なら、別系列として持つか、集約してよいかを考える。
順不同のデータを並べ替える場合は、xとyを同じ順序で並べる。xだけをソートすると、補間が通る代わりに標本の対応を壊す。欠測や無限大も事前に確認し、測定範囲、単位、軸方向を明示する。多チャンネルのyなら、xと対応するaxisも指定する必要がある。
外挿を明示的に禁止する
extrapolate=Falseにより、校正範囲より外の問い合わせにはNaNが返る。ここでは-0.5と3.5を評価し、両方とも欠測になることを確認した。範囲外で値が返らないという挙動を、呼び出し側でもエラーや未対応として扱う設計にしておく。
外挿が必要なら、標本点の端の曲線をそのまま延ばしてよい根拠が必要である。PCHIPの形状保持は、観測していない領域での物理的な正しさを保証しない。端の値へ固定する、範囲外を拒否する、別の理論モデルを使うなど、使用目的に合った方針を決める。
補間と平滑化の違いも意識する
補間は入力点を通るため、点にノイズがあればその影響も含めて通過する。単に曲線を滑らかに描いたから測定誤差が減ったわけではない。ノイズ低減やパラメータ推定が目的なら、平滑化やフィットなど別の方法を検討し、その仮定と残差を確認する。
PCHIPでは1階微分は連続だが、2階微分は節点で跳ぶ場合がある。高階微分や曲率を使う計算に適しているかは目的による。また、CubicSplineの行き過ぎ方は標本と境界条件に依存するため、この一例から常に不適切だと判断するべきではない。単調性、滑らかさ、外挿、誤差という要件を分けて方法を選ぼう。

動作確認環境と参考資料
Linux・CPython 3.12.14、NumPy 2.3.5、pandas 2.2.3、SciPy 1.17.0、Matplotlib 3.10.8の環境で掲載コードを実行した。使用するライブラリはコード冒頭のimportを参照してほしい。公式資料の最新版と、この実行確認版は区別している。数値の末尾や表の表示幅は環境によって変わることがある。
