scipy.optimize.

isotonic_regression#

scipy.optimize.isotonic_regression(y, *, weights=None, increasing=True)[Quelle]#

Nichtparametrische isotonische Regression.

Ein (nicht streng) monoton steigendes Array x mit der gleichen Länge wie y wird mit dem Pool-Adjacent-Violators-Algorithmus (PAVA) berechnet; siehe [1]. Weitere Details finden Sie im Abschnitt Hinweise.

Parameter:
y(N,) array_like

Antwortvariable.

weights(N,) array_like oder None

Fallgewichte.

increasingbool

Wenn True, wird eine monoton steigende, d.h. isotonische, Regression angepasst. Wenn False, wird eine monoton fallende, d.h. antitonische, Regression angepasst. Standard ist True.

Rückgabe:
resOptimizeResult

Das Optimierungsergebnis, dargestellt als ein OptimizeResult-Objekt. Wichtige Attribute sind

  • x: Die isotonische Regressionslösung, d.h. ein steigendes (oder fallendes) Array derselben Länge wie y, mit Elementen im Bereich von min(y) bis max(y).

  • weights : Array mit der Summe der Fallgewichte für jeden Block (oder Pool) B.

  • blocks: Array der Länge B+1 mit den Indizes der Startpositionen jedes Blocks (oder Pools) B. Der j-te Block ist gegeben durch x[blocks[j]:blocks[j+1]], für den alle Werte gleich sind.

Hinweise

Gegeben seien Daten \(y\) und Fallgewichte \(w\). Die isotonische Regression löst das folgende Optimierungsproblem:

\[\operatorname{argmin}_{x_i} \sum_i w_i (y_i - x_i)^2 \quad \text{unter der Bedingung } x_i \leq x_j \text{ wann immer } i \leq j \,.\]

Für jeden Eingabewert \(y_i\) wird ein Wert \(x_i\) erzeugt, so dass \(x\) steigend (aber nicht streng steigend) ist, d.h. \(x_i \leq x_{i+1}\). Dies wird durch PAVA erreicht. Die Lösung besteht aus Pools oder Blöcken, d.h. benachbarten Elementen von \(x\), z.B. \(x_i\) und \(x_{i+1}\), die alle den gleichen Wert haben.

Am interessantesten ist, dass die Lösung gleich bleibt, wenn der quadratische Verlust durch die breite Klasse von Bregman-Funktionen ersetzt wird, welche die einzigartige Klasse streng konsistenter Scoring-Funktionen für den Mittelwert darstellt, siehe [2] und die dortigen Referenzen.

Die implementierte Version von PAVA gemäß [1] hat eine rechnerische Komplexität von O(N) bei Eingabegröße N.

Referenzen

[1] (1,2)

Busing, F. M. T. A. (2022). Monotone Regression: A Simple and Fast O(n) PAVA Implementation. Journal of Statistical Software, Code Snippets, 102(1), 1-25. DOI:10.18637/jss.v102.c01

[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

Beispiele

Dieses Beispiel zeigt, dass isotonic_regression tatsächlich ein eingeschränktes Optimierungsproblem löst.

>>> 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      ])

Der große Vorteil von isotonic_regression im Vergleich zum Aufruf von minimize ist, dass es benutzerfreundlicher ist, d.h. man muss keine Zielfunktionen und Nebenbedingungen definieren, und dass es um Größenordnungen schneller ist. Auf handelsüblicher Hardware (im Jahr 2023) dauert die Minimierung für normalverteilte Eingabe y der Länge 1000 etwa 4 Sekunden, während isotonic_regression etwa 200 Mikrosekunden benötigt.