Pythonでn次元のデータを補間して利用する方法

Python

n次元のグリッド型のデータがあるときに、それを補間して使うやり方を探したけれど、いまいち見つからなかったのでメモ。

たとえば、次のようなデータがあったとする。

不快指数データ

湿度/気温 25 degC 30 degC 35 degC
70% 73.9 81.4 88.9
80% 74.9 82.9 90.9
90% 76 84.5 93
100% 77 86 95

このようなデータが与えられたとき、この表の値と値の間のデータを得たいとする。例えば27 degC, 湿度75%だと不快指数はいくらか、などという問題だ。1回この2次元の計算するだけなら手で計算するなり、いくらでも簡単にできるが、これを何百回もやるような場合は明らかによいライブラリを使ったほうがよい。また、4-5次元のデータだったりすると手で計算するのはかなり難しい。(ちなみに、実際には不快指数は計算式があるので表から内挿する必要はない)

このデータがdata.txtというファイルに入っているとする。

-	25	30 	35
70	73.9	81.4	88.9
80	74.9	82.9	90.9
90	76	84.5	93
100	77	86  	95

下記のコードで上記の線形補間が得られる。


from scipy.interpolate import RegularGridInterpolator
import numpy as np

data = np.genfromtxt("data.txt")

temperature = np.ascontiguousarray(data[0][1:])
humidity = np.ascontiguousarray(data.transpose()[0][1:])
dataset = data[1:].transpose()[1:].transpose()
disconfort_index = RegularGridInterpolator((humidity, temperature), dataset)

print(disconfort_index([[76, 26]]))

3次元以上の場合でも基本的にやることは変わらない。ただし、RegularGridInterpolatorで読み込む前にデータのshapeを整えてやる必要がある。上記のデータは4*3のmatrixで、2次元であった。

たとえば不快指数ではなく、体感温度のデータが与えられ、それを補間したいとする。体感温度は温度と湿度だけではなく風速の関数である。例えば次のようなデータが与えられたとする。

Temperature
Wind Speed Humidity 0 5 10 15 20 25 30 35 40
0
0 7.36 9.91 12.47 15.02 17.58 20.14 22.69 25.25 27.8
20 6.68 9.61 12.55 15.49 18.43 21.37 24.3 27.24 30.18
40 5.96 9.29 12.61 15.94 19.26 22.58 25.91 29.23 32.56
60 5.22 8.93 12.65 16.36 20.08 23.79 27.51 31.22 34.94
80 4.43 8.55 12.66 16.77 20.88 24.99 29.1 33.21 37.32
100 3.61 8.12 12.64 17.15 21.66 26.17 30.68 35.2 39.71
5
0 -7.3 -2.76 1.77 6.31 10.85 15.38 19.92 24.46 28.99
20 -8.83 -3.8 1.23 6.27 11.3 16.33 21.37 26.4 31.44
40 -10.48 -4.94 0.61 6.16 11.7 17.25 22.8 28.34 33.89
60 -12.25 -6.18 -0.1 5.98 12.05 18.13 24.2 30.28 36.35
80 -14.16 -7.53 -0.91 5.71 12.34 18.96 25.58 32.2 38.83
100 -16.22 -9.03 -1.83 5.36 12.55 19.74 26.93 34.12 41.31
10
0 -10.21 -5.28 -0.35 4.58 9.51 14.44 19.37 24.3 29.23
20 -11.95 -6.5 -1.04 4.41 9.87 15.32 20.78 26.23 31.69
40 -13.84 -7.84 -1.84 4.16 10.16 16.16 22.16 28.16 34.16
60 -15.87 -9.31 -2.74 3.82 10.39 16.95 23.52 30.08 36.65
80 -18.07 -10.92 -3.77 3.38 10.54 17.69 24.84 31.99 39.15
100 -20.47 -12.7 -4.94 2.83 10.59 18.36 26.13 33.89 41.66
15
0 -11.66 -6.53 -1.41 3.72 8.84 13.97 19.09 24.22 29.35
20 -13.52 -7.85 -2.18 3.48 9.15 14.82 20.48 26.15 31.82
40 -15.52 -9.3 -3.07 3.16 9.39 15.62 21.84 28.07 34.3
60 -17.7 -10.89 -4.07 2.74 9.55 16.36 23.17 29.98 36.79
80 -20.06 -12.64 -5.22 2.2 9.62 17.04 24.46 31.89 39.31
100 -22.63 -14.58 -6.52 1.54 9.6 17.66 25.72 33.78 41.84

このような3次元(またはn次元)のデータを補間するためには、読んだデータをreshapeで整えてやる必要がある。実際のデータは次のファイルで与えられたとする。

#temperature, 0, 5, 10, 15, 20, 25, 30, 35, 40
#humidity, 0, 20, 40, 60, 80, 100
#wind_speed, 0, 5, 10, 15

7.36,9.91,12.47,15.02,17.58,20.14,22.69,25.25,27.80
6.68,9.61,12.55,15.49,18.43,21.37,24.30,27.24,30.18
5.96,9.29,12.61,15.94,19.26,22.58,25.91,29.23,32.56
5.22,8.93,12.65,16.36,20.08,23.79,27.51,31.22,34.94
4.43,8.55,12.66,16.77,20.88,24.99,29.10,33.21,37.32
3.61,8.12,12.64,17.15,21.66,26.17,30.68,35.20,39.71
-7.30,-2.76,1.77,6.31,10.85,15.38,19.92,24.46,28.99
-8.83,-3.80,1.23,6.27,11.30,16.33,21.37,26.40,31.44
-10.48,-4.94,0.61,6.16,11.70,17.25,22.80,28.34,33.89
-12.25,-6.18,-0.10,5.98,12.05,18.13,24.20,30.28,36.35
-14.16,-7.53,-0.91,5.71,12.34,18.96,25.58,32.20,38.83
-16.22,-9.03,-1.83,5.36,12.55,19.74,26.93,34.12,41.31
-10.21,-5.28,-0.35,4.58,9.51,14.44,19.37,24.30,29.23
-11.95,-6.50,-1.04,4.41,9.87,15.32,20.78,26.23,31.69
-13.84,-7.84,-1.84,4.16,10.16,16.16,22.16,28.16,34.16
-15.87,-9.31,-2.74,3.82,10.39,16.95,23.52,30.08,36.65
-18.07,-10.92,-3.77,3.38,10.54,17.69,24.84,31.99,39.15
-20.47,-12.70,-4.94,2.83,10.59,18.36,26.13,33.89,41.66
-11.66,-6.53,-1.41,3.72,8.84,13.97,19.09,24.22,29.35
-13.52,-7.85,-2.18,3.48,9.15,14.82,20.48,26.15,31.82
-15.52,-9.30,-3.07,3.16,9.39,15.62,21.84,28.07,34.30
-17.70,-10.89,-4.07,2.74,9.55,16.36,23.17,29.98,36.79
-20.06,-12.64,-5.22,2.20,9.62,17.04,24.46,31.89,39.31
-22.63,-14.58,-6.52,1.54,9.60,17.66,25.72,33.78,41.84

この場合、次のようにやれば補間することができる。キモは、reshapeを使って補間する前に形を整えてやることである。

from scipy.interpolate import RegularGridInterpolator
import numpy as np
import pandas

data2 = pandas.read_csv("apparent_temp_data_.txt", header=None)
temperature = data2.iloc[0][1:]
humidity = data2.iloc[1][1:7]
wind_speed = data2.iloc[2][1:5]


dataset = np.array(data2[3:].dropna(axis="columns"), dtype=float)
dataset = dataset.reshape(len(wind_speed), len(humidity), len(temperature))


apparent_temp_index = RegularGridInterpolator((wind_speed, humidity, temperature), dataset)
print(apparent_temp_index([[3, 65, 22]]))

これで、風速3m/s, 湿度65%, 気温22degCのときの体感温度が求められる。このように形を整えてやることで、RegularGridInterpolatorが読めるようになる。これさえマスターすればn次元の問題が出てきても問題ない。外挿に関してはこのやり方はできないが、とりあえず内挿でよければこれだけでなんとかなる。

コメント

  1. pom2e より:

    コードが[crayon-5e61efd726391450103058/]のようになっていて見ることができないので、ぜひご確認いただけたらと思います。

  2. salamann より:

    修正しました。シンタックスハイライトのプラグインが他のプラグインと競合していたようだったので無効化しました。

  3. 群青蛙 より:

    こんにちは。
    本記事に記載の2次元の線型補間を参考にさせていただいています。
    サンプルコードをそのまま実行してみたのですが、”ValueError: ndarray is not C-contiguous”というエラーが出てしまいます。
    原因がよく分からず困っているのですが、何か分かりますでしょうか。
    随分前の記事へのコメントで恐縮ですが、よろしければお返事いただければと思います。
    こちらの環境は以下です。
    Python==3.9.7
    numpy==1.24.1
    scipy==1.10.0

    • salamann より:

      たしかに頂いた環境で実行してみるとValueError: ndarray is not C-contiguousというエラーが再現しました。C-contiguousになっていないといけないというエラーなので、C-contiguousになるようにコードを修正したところ、エラーが解消されました。試してみてください。

      • 群青蛙 より:

        迅速なお返事とコードの修正、本当にありがとうございました。
        いま試したところ、エラーが解消されました。大変助かりました!