scipy.optimize.

isotonic_regression#

scipy.optimize.isotonic_regression(y, *, веса=None, увеличивая=True)[источник]#

Непараметрическая изотоническая регрессия.

Массив (не строго) монотонно возрастающий x с той же длиной как y вычисляется алгоритмом pool adjacent violators (PAVA), см. [1]. См. раздел Примечания для более подробной информации.

Параметры:
y(N,) array_like

Зависимая переменная.

веса(N,) array_like или None

Веса наблюдений.

увеличиваяbool

Если True, подгоняет монотонно возрастающую, т.е. изотонную, регрессию. Если False, подгоняет монотонно убывающую, т.е. антитоническую, регрессию. По умолчанию True.

Возвращает:
resOptimizeResult

Результат оптимизации, представленный как OptimizeResult объект. Важные атрибуты:

  • x: Решение изотонной регрессии, т.е. возрастающий (или убывающий) массив той же длины, что и y, с элементами в диапазоне от min(y) до max(y).

  • weights : Массив с суммой весов случаев для каждого блока (или пула) B.

  • blocks: Массив длины B+1 с индексами начальных позиций каждого блока (или пула) B. j-й блок задаётся x[blocks[j]:blocks[j+1]] для которых все значения одинаковы.

Примечания

При заданных данных \(y\) и веса случаев \(w\), изотопическая регрессия решает следующую задачу оптимизации:

\[\operatorname{argmin}_{x_i} \sum_i w_i (y_i - x_i)^2 \quad \text{subject to } x_i \leq x_j \text{ whenever } i \leq j \,.\]

Для каждого входного значения \(y_i\), он генерирует значение \(x_i\) такой, что \(x\) возрастает (но не строго), т.е. \(x_i \leq x_{i+1}\). Это достигается с помощью PAVA. Решение состоит из пулов или блоков, т.е. соседних элементов \(x\), например, \(x_i\) и \(x_{i+1}\), которые все имеют одинаковое значение.

Наиболее интересно, что решение остаётся тем же, если квадратичная потеря заменяется широким классом функций Брегмана, которые являются единственным классом строго согласованных оценочных функций для среднего значения, см. [2] и ссылки в них.

Реализованная версия PAVA согласно [1] имеет вычислительную сложность O(N) при размере входных данных N.

Ссылки

[1] (1,2)

Busing, F. M. T. A. (2022). Монотонная регрессия: простая и быстрая реализация PAVA за O(n). Journal of Statistical Software, Code Snippets, 102(1), 1-25. #20247

[2]

Jordan, A.I., Mühlemann, A. & Ziegel, J.F. Characterizing the optimal solutions to the isotonic regression problem for identifiable functionals. Ann Inst Stat Math 74, 489-514 (2022). DOI:10.1007/s10463-021-00808-0

Примеры

Этот пример демонстрирует, что isotonic_regression фактически решает задачу условной оптимизации.

>>> import numpy as np
>>> from scipy.optimize import isotonic_regression, minimize
>>> y = [1.5, 1.0, 4.0, 6.0, 5.7, 5.0, 7.8, 9.0, 7.5, 9.5, 9.0]
>>> def objective(yhat, y):
...     return np.sum((yhat - y)**2)
>>> def constraint(yhat, y):
...     # This is for a monotonically increasing regression.
...     return np.diff(yhat)
>>> result = minimize(objective, x0=y, args=(y,),
...                   constraints=[{'type': 'ineq',
...                                 'fun': lambda x: constraint(x, y)}])
>>> result.x
array([1.25      , 1.25      , 4.        , 5.56666667, 5.56666667,
       5.56666667, 7.8       , 8.25      , 8.25      , 9.25      ,
       9.25      ])
>>> result = isotonic_regression(y)
>>> result.x
array([1.25      , 1.25      , 4.        , 5.56666667, 5.56666667,
       5.56666667, 7.8       , 8.25      , 8.25      , 9.25      ,
       9.25      ])

Большое преимущество isotonic_regression по сравнению с вызовом minimize в том, что он более удобен для пользователя, т.е. не нужно определять целевую функцию и функции ограничений, и он на порядки быстрее. На стандартном оборудовании (в 2023 году) для нормально распределенного входного y длиной 1000 минимизатор занимает около 4 секунд, в то время как isotonic_regression занимает около 200 микросекунд.