Pourquoi ne pas utiliser les «équations normales» pour trouver des coefficients de moindres carrés simples?

17

J'ai vu cette liste ici et je ne pouvais pas croire qu'il y avait tant de façons de résoudre les moindres carrés. Les «équations normales» sur Wikipédia semblaient être une méthode assez simple:

α^=y¯-β^X¯,β^=je=1n(Xje-X¯)(yje-y¯)je=1n(Xje-X¯)2

Alors pourquoi ne pas simplement les utiliser? J'ai supposé qu'il devait y avoir un problème de calcul ou de précision étant donné que dans le premier lien ci-dessus, Mark L. Stone mentionne que SVD ou QR sont des méthodes populaires dans les logiciels statistiques et que les équations normales sont "TERRIBLES du point de vue de la fiabilité et de la précision numérique". Cependant , dans le code suivant, les équations normales me donnent une précision à environ 12 décimales par rapport à trois fonctions python populaires: polyfit de numpy ; linregress de scipy ; et scikit-learn de régression linéaire .

Ce qui est plus intéressant, c'est que la méthode d'équation normale est la plus rapide lorsque n = 100000000. Les temps de calcul pour moi sont: 2,5 s pour linregress; 12,9 pour polyfit; 4.2s pour LinearRegression; et 1,8 s pour l'équation normale.

Code:

import numpy as np
from sklearn.linear_model import LinearRegression
from scipy.stats import linregress
import timeit

b0 = 0
b1 = 1
n = 100000000
x = np.linspace(-5, 5, n)
np.random.seed(42)
e = np.random.randn(n)
y = b0 + b1*x + e

# scipy                                                                                                                                     
start = timeit.default_timer()
print(str.format('{0:.30f}', linregress(x, y)[0]))
stop = timeit.default_timer()
print(stop - start)

# numpy                                                                                                                                      
start = timeit.default_timer()
print(str.format('{0:.30f}', np.polyfit(x, y, 1)[0]))
stop = timeit.default_timer()
print(stop - start)

# sklearn                                                                                                                                    
clf = LinearRegression()
start = timeit.default_timer()
clf.fit(x.reshape(-1, 1), y.reshape(-1, 1))
stop = timeit.default_timer()
print(str.format('{0:.30f}', clf.coef_[0, 0]))
print(stop - start)

# normal equation                                                                                                                            
start = timeit.default_timer()
slope = np.sum((x-x.mean())*(y-y.mean()))/np.sum((x-x.mean())**2)
stop = timeit.default_timer()
print(str.format('{0:.30f}', slope))
print(stop - start) 
Oliver Angelil
la source
Les réponses sont assez exagérées. Ce n'est pas si horrible si vous évitez simplement de calculer explicitement l'inverse.
mathreadler
3
Quelques remarques sur la vitesse: vous ne regardez qu'une seule covariable, donc le coût de l'inversion de matrice est essentiellement de 0. Si vous regardez quelques milliers de covariables, cela changera. Deuxièmement, parce que vous n'avez qu'une seule covariable, le munging de données est ce qui prend en fait beaucoup de votre temps chez les concurrents packagés (mais cela ne devrait évoluer que de manière linéaire, donc ce n'est pas grave). La solution d'équations normales ne fait pas de fusion de données, c'est donc plus rapide, mais n'a pas de cloches et de sifflets attachés à ses résultats.
Cliff AB

Réponses:

22

UNEXbUNEUNETUNElogdix(con)UNETUNEUNETUNEX=UNETblogdix(con(UNETUNE))=2logdix(con(UNE))

dix8dix16

Parfois, vous vous en sortez avec les équations normales, et parfois non.

Mark L. Stone
la source
2
Un moyen plus simple de le voir (si vous ne connaissez pas / ne vous souciez pas des numéros de condition) est que vous multipliez (essentiellement) quelque chose par lui-même ("en le mettant au carré"), ce qui signifie que vous pouvez vous attendre à perdre environ la moitié de vos bits de précision. (Cela devrait être plus évident si A est un scalaire, et il devrait être facile de voir que faire de A une matrice ne change pas vraiment le problème sous-jacent.)
user541686
Outre les différences de précision, existe-t-il également une grande différence de vitesse entre QR et les équations normales? parce que dans ce dernier cas, vous pourriez résoudre (X'X) -1 * X'Y, ce qui est lent à cause de l'inverse? Je demande parce que je ne sais pas comment fonctionne QR, alors peut-être qu'il y a quelque chose d'aussi lent que d'inverser une matrice. Ou le seul point à considérer est-il la perte de précision?
Simon
4
UNETUNEUNETb
8

Si vous n'avez qu'à résoudre ce problème à une variable, allez-y et utilisez la formule. Il n'y a rien de mal à cela. Je pourrais vous voir écrire quelques lignes de code dans ASM pour un périphérique intégré, par exemple. En fait, j'ai utilisé ce type de solution dans certaines situations. Vous n'avez pas besoin de faire glisser de grandes bibliothèques statistiques juste pour résoudre ce petit problème, bien sûr.

L'instabilité numérique et les performances sont des problèmes de problèmes plus importants et de cadre général. Si vous résolvez des moindres carrés multivariés, etc. Pour un problème général, vous ne l'utiliserez pas, bien sûr.

Aksakal
la source
0

Aucun progiciel statistique moderne ne résoudrait une régression linéaire avec les équations normales. Les équations normales n'existent que dans les livres statistiques.

Les équations normales ne doivent pas être utilisées car le calcul de l'inverse de la matrice est très problématique.

Pourquoi utiliser la descente de gradient pour la régression linéaire, lorsqu'une solution mathématique de forme fermée est disponible?

... bien que l'équation normale directe soit disponible. Notez que dans l'équation normale, il faut inverser une matrice. Maintenant, inverser une matrice coûte O (N3) pour le calcul où N est le nombre de lignes dans la matrice X, c'est-à-dire les observations. De plus, si le X est mal conditionné, cela créera des erreurs de calcul dans l'estimation ...

SmallChess
la source