Многомерная интерполяция?

У меня такие данные. Скорость по оси x и мощность по оси y. Это дает один сюжет. Но есть ряд значений C, которые дают другие графики также на диаграмме скорости и мощности.

Данные:

C = 12
speed:[127.1, 132.3, 154.3, 171.1, 190.7, 195.3]
power:[2800, 3400.23, 5000.1, 6880.7, 9711.1, 10011.2 ]

C = 14
speed:[113.1, 125.3, 133.3, 155.1, 187.7, 197.3]
power:[2420, 3320, 4129.91, 6287.17, 10800.34, 13076.5 ]

Теперь я хочу иметь возможность интерполяции в [[12.2, 122.1], [12.4, 137.3], [12.5, 154.9], [12.6, 171.4], [12.7, 192.6], [12.8, 198.5]] .

Я прочитал этот ответ. Я не уверен, что это способ сделать это.

Я старался:

data = np.array([[12, 127.1, 2800], [12, 132.3, 3400.23], [12, 154.3, 5000.1], [12, 171.1, 6880.7],
                [12, 190.7, 9711.1], [12, 195.3, 10011.2],
                [14, 113.1, 2420], [14, 125.3, 3320], [14, 133.3, 4129.91], [14, 155.1, 6287.17],
                [14, 187.7, 10800.34], [14, 197.3, 13076.5]])

coords = np.array([[12.2, 122.1], [12.4, 137.3], [12.5, 154.9], [12.6, 171.4], [12.7, 192.6], [12.8, 198.5]])

z = ndimage.map_coordinates(data, coords.T, order=2, mode='nearest')

но я получаю:

array([13076.5, 13076.5, 13076.5, 13076.5, 13076.5, 13076.5])

Я не уверен, как справиться с такой интерполяцией.

Всего 3 ответа


map_coordinates предполагает, что у вас есть элементы для каждого целочисленного индекса, вроде как в изображении. (0,1), (100, 0), (100, 1), (1, 1), (1, ..., (100, 100) - все координаты, которые хорошо определены, если у вас есть изображение 100x100. Это не ваше дело. У вас есть данные в координатах (12, 127.1), (12, 132.3) и т. Д.

griddata этого вы можете использовать griddata . В зависимости от того, как вы хотите интерполировать, вы получите разные результаты:

In [24]: data = np.array([[12, 127.1, 2800], [12, 132.3, 3400.23], [12, 154.3, 5000.1], [12, 171.1, 6880.7],
    ...:                 [12, 190.7, 9711.1], [12, 195.3, 10011.2],
    ...:                 [14, 113.1, 2420], [14, 125.3, 3320], [14, 133.3, 4129.91], [14, 155.1, 6287.17],
    ...:                 [14, 187.7, 10800.34], [14, 197.3, 13076.5]])

In [25]: from scipy.interpolate import griddata

In [28]: coords = np.array([[12.2, 122.1], [12.4, 137.3], [12.5, 154.9], [12.6, 171.4], [12.7, 192.6], [12.8, 198.5]])

In [29]: griddata(data[:, 0:2], data[:, -1], coords)
Out[29]:
array([           nan,  3895.22854545,  5366.64369048,  7408.68906748,
       10791.779     ,            nan])

In [31]: griddata(data[:, 0:2], data[:, -1], coords, method='nearest')
Out[31]: array([ 3320.  ,  4129.91,  5000.1 ,  6880.7 ,  9711.1 , 13076.5 ])

In [32]: griddata(data[:, 0:2], data[:, -1], coords, method='cubic')
Out[32]:
array([           nan,  3998.75479082,  5357.54672326,  7297.94115979,
       10647.04183455,            nan])

method='cubic' вероятно, имеет наивысшую точность для «случайных» данных, но только вы можете решить, какой метод подходит для ваших данных и что вы пытаетесь сделать (по умолчанию method='linear' , используемый в [29] выше).

Обратите внимание, что некоторые ответы - nan . Это связано с тем, что вы внесли ввод, который не находится внутри «ограничивающего многоугольника», который ваши точки образуют в 2D-пространстве.

Вот визуализация, чтобы показать вам, что я имею в виду:

In [49]: x = plt.scatter(x=np.append(data[:, 0], [12.2, 12.8]), y=np.append(data[:, 1], [122.1, 198.5]), c=['green']*len(data[:, 0]) + ['red']*2)

In [50]: plt.show()

ограничивающий многоугольник

Я не связывал точки зеленым цветом, но вы можете видеть, что две точки красного цвета находятся за пределами многоугольника, который будет сформирован, если бы я связал эти точки. Вы не можете интерполировать вне этого диапазона, так что вы получаете nan . Чтобы понять, почему, рассмотрим 1-й случай. Если я спрошу вас, что такое значение в индексе 2.5 из [0,1,2,3] , разумный ответ будет 2.5 . Однако, если я спрошу, что находится в значении индекса 100 ... априори, мы понятия не имеем, что в 100, это слишком далеко от диапазона того, что вы можете видеть. Поэтому мы не можем дать ответ. Говорить, что это 100 , неправильно для этой функциональности, поскольку это будет экстраполяция , а не интерполяция .

НТН.


Предполагая, что ваша функция имеет форму power = F (C, speed), вы можете использовать scipy.interpolate.interp2d :

import scipy.interpolate as sci

speed = [127.1, 132.3, 154.3, 171.1, 190.7, 195.3]
C = [12]*len(speed)
power = [2800, 3400.23, 5000.1, 6880.7, 9711.1, 10011.2 ]

speed += [113.1, 125.3, 133.3, 155.1, 187.7, 197.3]
C += [14]*(len(speed) - len(C))
power += [2420, 3320, 4129.91, 6287.17, 10800.34, 13076.5 ]

f = sci.interp2d(C, speed, power)

coords = np.array([[12.2, 122.1], [12.4, 137.3], [12.5, 154.9], [12.6, 171.4], [12.7, 192.6], [12.8, 198.5]])
power_interp = np.concatenate([f(*coord) for coord in coords])

with np.printoptions(precision=1, suppress=True, linewidth=9999):
    print(power_interp)

Эти результаты:

[1632.4 2659.5 3293.4 4060.2 5074.8 4506.6]

который кажется немного низким. Причиной этого является то, что interp2d по умолчанию использует линейный сплайн, и ваши данные определенно нелинейны. Вы можете получить лучшие результаты, напрямую LSQBivariateSpline подпрограмме сплайн-аппроксимации через LSQBivariateSpline :

xknots = (min(C), max(C))
yknots = (min(speed), max(speed))
f = sci.LSQBivariateSpline(C, speed, power, tx=xknots, ty=yknots, kx=2, ky=3)

power_interp = f(*coords.T, grid=False)

with np.printoptions(precision=1, suppress=True, linewidth=9999):
    print(power_interp)

Эти результаты:

[ 2753.2  3780.8  5464.5  7505.2 10705.9 11819.6]

что представляется более разумным.


Мне кажется, что все, что у вас есть, это:

скорость = F (C) и мощность = G (C)

Таким образом, вам не нужна многомерная интерполяция, просто interp1d для создания одной функции для скорости, а другая для питания ...


Есть идеи?

10000