</>
Topic 1 of 5

Course materials are currently available in Russian only.

Корни и минимумы

SciPy — большая библиотека научных вычислений поверх numpy. Она разбита на модули: scipy.optimize (оптимизация), scipy.integrate (интегралы), scipy.stats (статистика), scipy.interpolate, scipy.linalg и другие. Каждый модуль импортируют отдельно:

from scipy.optimize import brentq, minimize_scalar, minimize, curve_fit

В этой теме — две самые частые задачи: найти, где функция равна нулю, и найти, где она наименьшая.

Функции как аргументы

Почти все функции SciPy принимают другую функцию — ту, корень или минимум которой ищем. Её можно описать через def или коротко через lambda:

def f(x):
    return x ** 3 - 2 * x - 5

g = lambda x: x ** 3 - 2 * x - 5     # то же самое

Корень на отрезке: brentq

brentq(f, a, b) находит x на отрезке [a, b], для которого f(x) = 0. Условие: f(a) и f(b) разного знака — тогда корень внутри точно есть.

from scipy.optimize import brentq

f = lambda x: x ** 3 - 2 * x - 5
print(f(2), f(3))          # -1 и 16: знаки разные
print(brentq(f, 2, 3))     # 2.0945514815423265

Метод быстрый и надёжный: он сочетает деление отрезка пополам с более «умными» шагами и находит корень с точностью около 10-12. Если знаки одинаковые, будет ошибка ValueError.

Для уравнений с параметрами удобно, что lambda «видит» переменные вокруг:

k = 7
print(brentq(lambda x: x * x - k, 0, k))   # √7

Есть и универсальная обёртка root_scalar(f, bracket=[a, b]), а для систем уравнений — fsolve.

Минимум функции одной переменной: minimize_scalar

from scipy.optimize import minimize_scalar

res = minimize_scalar(lambda x: x ** 2 - 6 * x + 13, bounds=(0, 10), method="bounded")
print(res.x)      # точка минимума ≈ 3
print(res.fun)    # значение в ней ≈ 4

Результат — объект с полями: x (где минимум), fun (значение), success (удалось ли).

method="bounded" ищет минимум строго внутри bounds. Без границ метод может «убежать» туда, где формула теряет смысл, — например, к отрицательным значениям, если функция определена только для x &gt; 0. Точность по умолчанию — около 10-5 по x; её можно увеличить: options={"xatol": 1e-9}.

Минимум функции многих переменных: minimize

from scipy.optimize import minimize

f = lambda p: (p[0] - 1) ** 2 + (p[1] + 2) ** 2   # p — массив из двух чисел
res = minimize(f, x0=[0, 0])
print(res.x)      # ≈ [1, -2]

x0 — начальная точка поиска. Метод двигается от неё «под горку», поэтому, если у функции несколько ям, найдётся ближайшая подходящая — не обязательно самая глубокая.

Подбор параметров формулы: curve_fit

Частая задача: есть измерения и формула с неизвестными параметрами. Нужно подобрать параметры так, чтобы формула лучше всего проходила через точки, то есть сумма квадратов отклонений была минимальна (метод наименьших квадратов).

import numpy as np
from scipy.optimize import curve_fit

def model(t, k, b):            # первый аргумент — x, остальные — параметры
    return k * np.sqrt(t) + b

t = np.array([0, 1, 4, 9, 16])
y = np.array([1.1, 3.0, 4.9, 7.2, 8.9])
params, cov = curve_fit(model, t, y, p0=(1, 0))
print(params)                  # подобранные k и b
  • функция-модель должна работать с массивами numpy — поэтому np.sqrt, np.exp, а не math;
  • p0 — начальное приближение параметров (по умолчанию все единицы);
  • вторая часть результата — оценка ковариации параметров, её часто игнорируют: params, _ = curve_fit(...).

Итог

  • brentq(f, a, b) — корень на отрезке, где знаки на концах разные;
  • minimize_scalar(f, bounds=(l, r), method="bounded") — минимум на отрезке; res.x, res.fun;
  • minimize(f, x0) — минимум функции многих переменных от начальной точки;
  • curve_fit(model, x, y, p0=...) — параметры формулы по методу наименьших квадратов.