補間 scipy.interpolate.interp1d おさらい

**実行環境**
Windows10, Python 3.9.5, scipy 1.7.0

## はじめに
SciPy の [interpolate](https://docs.scipy.org/doc/scipy/reference/interpolate.html) モジュールには、多様な補間法に対応したクラスや関数が用意されています。

ここではその中の [interp1d](https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.interp1d.html) クラスを取り上げます。

投稿時点の scipy の最新リリースバージョンは 1.7.3 ですが、本稿はバージョン 1.7.0 をもとにしています。

## 補間
数学的な定義よく分かりませんが、補間とは「既知点の間の値を推定すること」というのが私の根本的な理解です。

補間はあくまで推定なのでその方法もいろいろとあるわけですが、その中で最もシンプルな方法が線形補間です。

折れ線グラフは一連の既知点の間を直線で結んで表現しますが、その直線を引くこと、あるいはその直線上の値を求めることが線形補間になります。

また、既知点の間を直線で結ぶ以外に nearest や spline といった種類の補間もあります。

次元を１つあげれば平面でも同じ話ができますが、ここでは１次元の補間を扱います。

なお、補完と誤字りそうになりますが、正しくは間を補うと書いて補間です。

## 簡単な例
[公式リファレンス](https://docs.scipy.org/doc/scipy/reference/interpolate.html)の Examples を転載します。

```py
import matplotlib.pyplot as plt
from scipy import interpolate

x = np.arange(0, 10)
y = np.exp(-x/3.0)
f = interpolate.interp1d(x, y)

xnew = np.arange(0, 9, 0.1)
ynew = f(xnew)   # use interpolation function returned by `interp1d`
plt.plot(x, y, 'o', xnew, ynew, '-')
plt.show()
```

![scipy-interpolate-interp1d-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1409923/8dd1a5a8-87d6-a6ea-7c71-3c8e3ffa11e0.png)


f は x と y を引数として interp1d クラスをインスタンス化したものです。

先ほどの例でいくと、この f が折れ線グラフになります。

f はインスタンスですが、特殊メソッド \_\_call__ によって関数のように働き、引数に x の配列を渡すことで補間された y の配列を返してくれます。


## interp1d の構文
scipy.interpolate.interp1d は、補間処理を実行してくれるインスタンスを生成します。

```py
scipy.interpolate.interp1d(
    x, y,
    kind='linear',
    axis=-1,
    copy=True,
    bounds_error=None,
    fill_value=nan,
    assume_sorted=False
    )
```
## interp1d の引数
引数について簡単に説明します。
詳細は公式リファレンス等をご確認ください。

### x
既知点の x を list, tuple, np.ndarray, pd.Series などの一次元配列で指定します。

### y
既知点の y を配列で指定します。

y のデータ数と x のデータ数が違うと ValueError になります。

なお、 y は多次元配列でも構いません。

２次元配列を指定して、同じ平面グラフ上に複数の折れ線グラフを描くというようなことができます。

### kind
ここに補間方法を指定します。

デフォルトが線形補間です。

| kind | 説明 |
|:-|:-|
| 'linear' | デフォルト、線形補間 |
| 'nearest' | 最近隣（中間点には直前の既知点の y を採用） |
| 'nearest-up' | 最近隣（中間点には直後の既知点の y を採用） |
| 'zero' | 0次スプライン補間 |
| 'slinear' | 1次スプライン補間 |
| 'quadratic' | 2次スプライン補間 |
| 'cubic' | 3次スプライン補間 |
| 'previous' | 直前の既知点の y を採用 |
| 'next' | 直後の既知点の y を採用 |

それぞれの補間方法の違いは、[公式ユーザガイド](https://docs.scipy.org/doc/scipy/tutorial/interpolate.html)に載っている以下のグラフが分かりやすいです。

![interpolate-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1409923/4bb7bd3c-78c8-642b-1368-2a9a1aebafd7.png)

![interpolate-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1409923/22380a23-bc51-88a5-b78e-76619253fdc2.png)


### axis
y に多次元配列を指定する場合は、ここで軸を指定できます。

デフォルトは axis=-1 で、２次元配列の場合は axis=1 になります。

従って、２次元配列の縦方向に y が入っている場合は axis=0 を指定します。

指定した軸のデータ数と x のデータ数が一致しない場合 ValueError です。

### copy
x, y を値とするか、参照とするかを指定します。

デフォルトは True で、 x, y は値（コピー）として扱われます。

### bounds_error
外挿をエラーとするかどうかを指定します。

bounds_error=True を指定した場合は、外挿しようとすると ValueError となります。

外挿する場合は bounds_error=False と併せて、後述の fill_value で外挿方法を指定します。

bounds_error を指定しない場合は、fill_value='extrapolate' を指定しない限り ValueError になります。
（bounds_error を指定しなくても、fill_value='extrapolate' とすれば外挿処理される）

### fill_value
bounds_error=Falseのときの外挿方法を指定します。

デフォルトは nan が外挿値となり、実質的に x の範囲外は補間されません。

外挿する場合は、fill_value='extrapolate' を指定します。

数値を指定すると、外挿値がすべて指定の数値になります。

要素数 2 のタプルを指定すると、小さい側の外挿値には1つ目の要素が、大きい側の外挿値には2つ目の要素が割り当てられます。

配列が複数の場合、タプルをネストして渡すと、それぞれの配列の上下の外挿値を個別に指定できます。

### assume_sorted
x が昇順ソートされていることを想定するかどうかを指定します。

デフォルトは False で、x が昇順でない場合に自動的に x, y の組み合わせが x で昇順ソートされます。

True を指定すると、x が昇順でない場合に ValueError が出ます。

### 注意点
[公式リファレンス](https://docs.scipy.org/doc/scipy/reference/interpolate.html)の Notes にある通り、x, y の中に NaN がある場合や x の中で重複があると、期待の結果とならない場合があるということです。

x, y にはキレイなデータを使いましょう。

## 最後に
scipy.interpolate.interp1d について、おさらいをしました。

y は多次元でも扱えますが、軸の指定やデータの個数などに気をつける必要があります。

また、外挿が発生するときの振る舞いも、引数の取り方によって異なるため注意です。

なお、ここでは SciPy を使っていますが、pandas.DataFrame のメソッドにも [interpolate](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.interpolate.html) があって補間処理ができるので、どちらを使うかはお好みで。