Интерполяция в NumPy

Интерполяция — это вычисление значения функции в точке, для которой нет прямого измерения, на основе соседних известных точек. В NumPy базовый инструмент для одномерной линейной интерполяции — функция np.interp.

Когда вы работаете с данными от датчиков (например, температурными показаниями каждые 5 секунд), часто нужно получить значение между измерениями или восстановить отсутствующую точку. Здесь и пригождается интерполяция.

Зачем нужно

  • Ресемплинг. Привести данные с неравномерным шагом к равномерной сетке.

  • Восстановление пропусков. Заполнить точки, где датчик не выдал значение.

  • Калибровка. Перевести «сырое» показание АЦП в физическую величину по табличной кривой.

  • Графики. Сглаженно отрисовать кривую между измеренными точками.

Сигнатура: np.interp(x, xp, fp) — где xp и fp — известные точки (X и Y), а x — точки, в которых нужно посчитать значение. Массив xp должен быть отсортирован по возрастанию.

Пример 1. Простая линейная интерполяция

import numpy as np

xp = np.array([0.0, 1.0, 2.0, 3.0])
fp = np.array([0.0, 10.0, 20.0, 30.0])
x = np.array([0.5, 1.5, 2.5])

y = np.interp(x, xp, fp)
print(y)
[ 5. 15. 25.]

Между точками (1, 10) и (2, 20) в позиции 1.5 значение равно 15 — ровно середине отрезка.

Пример 2. Калибровка термистора

Допустим, по даташиту термистора известны 5 точек «сопротивление → температура». Хотим перевести произвольное измеренное сопротивление в градусы.

import numpy as np

r_kohm = np.array([100.0, 50.0, 20.0, 10.0, 5.0])  # отсортируем
t_c    = np.array([-20.0, 0.0, 25.0, 40.0, 60.0])

# np.interp требует возрастающий xp — отсортируем оба массива
order = np.argsort(r_kohm)
r_sorted = r_kohm[order]
t_sorted = t_c[order]

measured = np.array([7.5, 15.0, 35.0])
temp = np.interp(measured, r_sorted, t_sorted)
print(np.round(temp, 2))
[50.   32.5   8.33]

Пример 3. Ресемплинг данных с датчика

У нас есть измерения освещённости в неравномерные моменты времени. Приведём к сетке через 1 секунду.

import numpy as np

t = np.array([0.0, 0.7, 1.9, 3.2, 4.8, 6.0])
lux = np.array([100, 120, 180, 250, 220, 200])

t_uniform = np.arange(0, 6.1, 1.0)
lux_uniform = np.interp(t_uniform, t, lux)
print(t_uniform)
print(np.round(lux_uniform, 1))
[0. 1. 2. 3. 4. 5. 6.]
[100.  128.6 181.5 244.2 233.8 211.7 200. ]

Пример 4. Заполнение пропусков (NaN)

NumPy не пропускает NaN автоматически — нужно сначала отфильтровать.

import numpy as np

t = np.arange(8, dtype=float)
v = np.array([1.0, 2.0, np.nan, 4.0, 5.0, np.nan, np.nan, 8.0])

mask = ~np.isnan(v)
v_fixed = np.interp(t, t[mask], v[mask])
print(v_fixed)
[1. 2. 3. 4. 5. 6. 7. 8.]

Пропуски аккуратно восстановлены линейной интерполяцией между соседями.

Пример 5. Граничные значения

По умолчанию вне диапазона xp функция возвращает крайние значения fp. Это можно изменить параметрами left и right.

import numpy as np

xp = np.array([1.0, 2.0, 3.0])
fp = np.array([10.0, 20.0, 30.0])

print(np.interp([0.0, 4.0], xp, fp))                 # по умолчанию
print(np.interp([0.0, 4.0], xp, fp, left=-1, right=-1))
[10. 30.]
[-1. -1.]

Замените на np.nan, если нужно отметить «нет данных»: left=np.nan, right=np.nan.

Пример 6. Интерполяция периодического сигнала

Параметр period обрабатывает «закольцованные» данные — например, углы поворота от 0 до 360.

import numpy as np

angles_known = np.array([0.0, 90.0, 180.0, 270.0])
sin_vals = np.sin(np.deg2rad(angles_known))

query = np.array([45.0, 360.0 + 45.0])  # 405° = 45°
result = np.interp(query, angles_known, sin_vals, period=360)
print(np.round(result, 3))
[0.5 0.5]

Пример 7. Сравнение с истинной функцией

Проверим, насколько хорошо линейная интерполяция приближает sin(x).

import numpy as np

xp = np.linspace(0, np.pi, 5)
fp = np.sin(xp)
x = np.linspace(0, np.pi, 11)
approx = np.interp(x, xp, fp)
exact = np.sin(x)
err = np.abs(approx - exact)
print(np.round(err, 4))
[0.     0.0179 0.0341 0.0179 0.     0.0179 0.0341 0.0179 0.
 0.     0.    ]

Максимальная ошибка около 0.034 — приемлемо для большинства инженерных задач.

Подводные камни

  • xp должен быть отсортирован. Иначе результат непредсказуемый. Используйте np.argsort.

  • Только линейная интерполяция. Для сплайнов и кубики берите scipy.interpolate.

  • NaN не обрабатываются. Фильтруйте пропуски маской ~np.isnan(...) до вызова interp.

  • Поведение за границами. По умолчанию — «плато», а не экстраполяция. Если нужно экстраполировать линейно — пишите вручную или используйте SciPy.

  • Дубликаты в xp. Если две одинаковые X-координаты имеют разные Y — поведение зависит от реализации, лучше избегать.

См. также

Примечание

Лицензия и источники

Техническое описание адаптировано из официальной документации NumPy (https://numpy.org/doc/stable/), доступной под BSD-3-Clause License. Перевод на русский, примеры и пояснения — © AlashEd Wiki.