Интерполяция в 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 — создание массивов данных
Векторизация в NumPy — векторизованные операции
Универсальные функции (ufunc) — поэлементные функции
Примечание
Лицензия и источники
Техническое описание адаптировано из официальной документации NumPy (https://numpy.org/doc/stable/), доступной под BSD-3-Clause License. Перевод на русский, примеры и пояснения — © AlashEd Wiki.