Ich habe ursprünglich die folgenden Benchmarks mit dem Ziel veröffentlicht, zu empfehlen numpy.corrcoef
, dummerweise nicht zu erkennen, dass die ursprüngliche Frage bereits verwendet wird corrcoef
und tatsächlich nach Polynomanpassungen höherer Ordnung gefragt hat. Ich habe eine tatsächliche Lösung für die Polynom-R-Quadrat-Frage mithilfe von Statistikmodellen hinzugefügt und die ursprünglichen Benchmarks beibehalten, die zwar nicht zum Thema gehören, aber möglicherweise für jemanden nützlich sind.
statsmodels
hat die Fähigkeit, die r^2
Polynomanpassung direkt zu berechnen , hier sind 2 Methoden ...
import statsmodels.api as sm
import statsmodels.formula.api as smf
# Construct the columns for the different powers of x
def get_r2_statsmodels(x, y, k=1):
xpoly = np.column_stack([x**i for i in range(k+1)])
return sm.OLS(y, xpoly).fit().rsquared
# Use the formula API and construct a formula describing the polynomial
def get_r2_statsmodels_formula(x, y, k=1):
formula = 'y ~ 1 + ' + ' + '.join('I(x**{})'.format(i) for i in range(1, k+1))
data = {'x': x, 'y': y}
return smf.ols(formula, data).fit().rsquared # or rsquared_adj
Um dies weiter zu nutzen statsmodels
, sollte man sich auch die angepasste Modellzusammenfassung ansehen, die in Jupyter / IPython-Notizbuch gedruckt oder als umfangreiche HTML-Tabelle angezeigt werden kann. Das Ergebnisobjekt bietet zusätzlich Zugriff auf viele nützliche statistische Metriken rsquared
.
model = sm.OLS(y, xpoly)
results = model.fit()
results.summary()
Unten ist meine ursprüngliche Antwort, in der ich verschiedene lineare Regressionsmethoden verglichen habe ...
Die in der Frage verwendete Corrcoef- Funktion berechnet den Korrelationskoeffizienten r
nur für eine einzelne lineare Regression, sodass die Frage r^2
nach Polynomanpassungen höherer Ordnung nicht behandelt wird . Für das, was es wert ist, habe ich jedoch festgestellt, dass es für die lineare Regression tatsächlich die schnellste und direkteste Berechnungsmethode ist r
.
def get_r2_numpy_corrcoef(x, y):
return np.corrcoef(x, y)[0, 1]**2
Dies waren meine zeitlichen Ergebnisse aus dem Vergleich einer Reihe von Methoden für 1000 zufällige (x, y) Punkte:
- Pure Python (direkte
r
Berechnung)
- 1000 Schleifen, am besten 3: 1,59 ms pro Schleife
- Numpy Polyfit (anwendbar auf Polynomanpassungen n-ten Grades)
- 1000 Schleifen, am besten 3: 326 µs pro Schleife
- Numpy Manual (direkte
r
Berechnung)
- 10000 Schleifen, am besten 3: 62,1 µs pro Schleife
- Numpy Corrcoef (direkte
r
Berechnung)
- 10000 Schleifen, am besten 3: 56,6 µs pro Schleife
- Scipy (lineare Regression mit
r
als Ausgabe)
- 1000 Schleifen, am besten 3: 676 µs pro Schleife
- Statistikmodelle (können Polynome n-ten Grades und viele andere Anpassungen ausführen)
- 1000 Schleifen, am besten 3: 422 µs pro Schleife
Die Corrcoef-Methode schlägt die Berechnung des r ^ 2 "manuell" mit Numpy-Methoden knapp. Es ist> 5X schneller als die Polyfit-Methode und ~ 12X schneller als die scipy.linregress. Nur um zu verstärken, was Numpy für Sie tut, ist es 28-mal schneller als reines Python. Ich bin mit Dingen wie Numba und Pypy nicht vertraut, daher müsste jemand anderes diese Lücken füllen, aber ich denke, das überzeugt mich sehr, dass dies corrcoef
das beste Werkzeug für die Berechnung r
einer einfachen linearen Regression ist.
Hier ist mein Benchmarking-Code. Ich habe von einem Jupyter-Notizbuch kopiert (es ist schwer, es nicht als IPython-Notizbuch zu bezeichnen ...), also entschuldige ich mich, wenn unterwegs etwas kaputt gegangen ist. Der Befehl% timeit magic erfordert IPython.
import numpy as np
from scipy import stats
import statsmodels.api as sm
import math
n=1000
x = np.random.rand(1000)*10
x.sort()
y = 10 * x + (5+np.random.randn(1000)*10-5)
x_list = list(x)
y_list = list(y)
def get_r2_numpy(x, y):
slope, intercept = np.polyfit(x, y, 1)
r_squared = 1 - (sum((y - (slope * x + intercept))**2) / ((len(y) - 1) * np.var(y, ddof=1)))
return r_squared
def get_r2_scipy(x, y):
_, _, r_value, _, _ = stats.linregress(x, y)
return r_value**2
def get_r2_statsmodels(x, y):
return sm.OLS(y, sm.add_constant(x)).fit().rsquared
def get_r2_python(x_list, y_list):
n = len(x)
x_bar = sum(x_list)/n
y_bar = sum(y_list)/n
x_std = math.sqrt(sum([(xi-x_bar)**2 for xi in x_list])/(n-1))
y_std = math.sqrt(sum([(yi-y_bar)**2 for yi in y_list])/(n-1))
zx = [(xi-x_bar)/x_std for xi in x_list]
zy = [(yi-y_bar)/y_std for yi in y_list]
r = sum(zxi*zyi for zxi, zyi in zip(zx, zy))/(n-1)
return r**2
def get_r2_numpy_manual(x, y):
zx = (x-np.mean(x))/np.std(x, ddof=1)
zy = (y-np.mean(y))/np.std(y, ddof=1)
r = np.sum(zx*zy)/(len(x)-1)
return r**2
def get_r2_numpy_corrcoef(x, y):
return np.corrcoef(x, y)[0, 1]**2
print('Python')
%timeit get_r2_python(x_list, y_list)
print('Numpy polyfit')
%timeit get_r2_numpy(x, y)
print('Numpy Manual')
%timeit get_r2_numpy_manual(x, y)
print('Numpy corrcoef')
%timeit get_r2_numpy_corrcoef(x, y)
print('Scipy')
%timeit get_r2_scipy(x, y)
print('Statsmodels')
%timeit get_r2_statsmodels(x, y)