Интерполяция: восстанавливаем значения между точками
У нас есть значения функции в нескольких точках — а нужно значение между ними. Это задача интерполяции.
Интерполяция — построение функции, которая проходит ровно через заданные точки и позволяет оценить значение между ними.
Зачем это нужно
Измерения почти всегда дискретны: температура раз в час, курс раз в день, датчик раз в миллисекунду. А вопросы возникают про промежуток: «какая была температура в 14:30, если меряли в 14:00 и 15:00?». Интерполяция отвечает на это, проводя гладкую кривую через известные точки. Важно не путать с экстраполяцией (выход за пределы данных — гораздо рискованнее) и с аппроксимацией (приближение, которое НЕ обязано проходить через точки).
Линейная интерполяция: простейший случай
Между двумя соседними точками (x0, y0) и (x1, y1) проводим прямую. Значение в точке x внутри отрезка:
y = y0 + (y1 - y0) * (x - x0) / (x1 - x0)
Геометрически — «доля пути» от x0 к x1 определяет, насколько y ушёл от y0 к y1.
Реализация на чистом Python
Найдём нужный отрезок и применим формулу — всё на stdlib, реально работает:
xs = [0.0, 1.0, 2.0, 3.0]
ys = [0.0, 1.0, 4.0, 9.0] # это y = x^2 в узлах
def interp(x):
# ищем отрезок [xs[i], xs[i+1]], содержащий x
for i in range(len(xs) - 1):
if xs[i] <= x <= xs[i + 1]:
x0, x1 = xs[i], xs[i + 1]
y0, y1 = ys[i], ys[i + 1]
return y0 + (y1 - y0) * (x - x0) / (x1 - x0)
raise ValueError("x вне диапазона")
print("Точно x^2 при 1.5 =", 1.5 ** 2)
print("Линейная оценка =", interp(1.5))
Вывод:
Точно x^2 при 1.5 = 2.25 Линейная оценка = 2.5
Заметьте: линейная интерполяция дала 2.5 вместо точного 2.25 — прямая «срезает» кривизну параболы. Чем гуще узлы, тем меньше ошибка.
Сплайны: гладко, как лекало
Линейная интерполяция даёт «ломаную» с изломами в узлах. Чтобы было гладко, используют кубические сплайны: между каждой парой точек проводят кубический многочлен, причём так, чтобы в узлах совпадали не только значения, но и первая и вторая производные. Результат — кривая без изломов, как если бы вы гнули гибкое лекало (само слово spline — гибкая чертёжная рейка).
| Метод | Гладкость | Цена |
| Линейная | изломы в узлах | дёшево, просто |
| Кубический сплайн | гладкая, без изломов | чуть дороже, нужно решить систему |
А в SciPy — одна строка
SciPy умеет и линейную, и сплайны (код для чтения, не запускается):
import numpy as np
from scipy.interpolate import interp1d, CubicSpline
xs = np.array([0, 1, 2, 3])
ys = xs ** 2
f_lin = interp1d(xs, ys, kind="linear")
f_cub = CubicSpline(xs, ys)
print(f_lin(1.5)) # 2.5 — как у нас руками
print(f_cub(1.5)) # 2.25 — сплайн точно ложится на параболу
Как работает под капотом
Кубический сплайн требует решить систему уравнений: на N узлах — N−1 кубических кусков, у каждого 4 коэффициента, итого много неизвестных. Условия (значения в узлах + непрерывность первой и второй производных + краевые условия) дают ровно столько же уравнений. Получается трёхдиагональная система — её решают за O(N), очень быстро. Вот почему сплайн «чуть дороже» линейной интерполяции, но всё равно практически мгновенный даже на тысячах точек.
Частые ошибки
- Путать интерполяцию с экстраполяцией. За пределами данных кубический сплайн может «выстрелить» в абсурдные значения.
- Интерполировать шумные данные. Если в y есть шум, интерполяция честно протащит кривую через каждую помеху — лучше аппроксимация (сглаживание).
- Неотсортированные узлы. И наш код, и SciPy ждут возрастающие
xs.
Итог
- Интерполяция строит функцию, проходящую через заданные точки.
- Линейная проста, но даёт изломы; кубический сплайн — гладкий, ценой решения системы.
- «Руками» легко делается линейная; сплайны и прочее —
scipy.interpolate. - Не путайте с экстраполяцией (рискованно) и аппроксимацией (не проходит через точки).