Originalmente publiqué los puntos de referencia a continuación con el propósito de recomendar numpy.corrcoef
, tontamente sin darme cuenta de que la pregunta original ya se usa corrcoef
y, de hecho, preguntaba acerca de los ajustes polinomiales de orden superior. Agregué una solución real a la pregunta del polinomio r-cuadrado usando modelos de estadísticas, y dejé los puntos de referencia originales, que aunque están fuera del tema, son potencialmente útiles para alguien.
statsmodels
tiene la capacidad de calcular el r^2
ajuste de un polinomio directamente, aquí hay 2 métodos ...
import statsmodels.api as sm
import statsmodels.formula.api as smf
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
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
Para aprovechar aún más statsmodels
, también se debe mirar el resumen del modelo ajustado, que puede imprimirse o mostrarse como una tabla HTML enriquecida en el cuaderno Jupyter / IPython. El objeto de resultados proporciona acceso a muchas métricas estadísticas útiles además de rsquared
.
model = sm.OLS(y, xpoly)
results = model.fit()
results.summary()
A continuación se muestra mi respuesta original donde comparé varios métodos de regresión lineal r ^ 2 ...
La función corrcoef utilizada en la Pregunta calcula el coeficiente de correlación r
, solo para una regresión lineal simple, por lo que no aborda la cuestión de r^2
los ajustes de polinomios de orden superior. Sin embargo, por lo que vale, he llegado a encontrar que para la regresión lineal, es de hecho el método de cálculo más rápido y directo r
.
def get_r2_numpy_corrcoef(x, y):
return np.corrcoef(x, y)[0, 1]**2
Estos fueron los resultados de mi tiempo al comparar varios métodos para 1000 puntos aleatorios (x, y):
- Python puro (
r
cálculo directo )
- 1000 bucles, lo mejor de 3: 1,59 ms por bucle
- Numpy polyfit (aplicable a ajustes polinomiales de n-ésimo grado)
- 1000 bucles, lo mejor de 3: 326 µs por bucle
- Numpy Manual (
r
cálculo directo )
- 10000 bucles, lo mejor de 3: 62,1 µs por bucle
- Numpy corrcoef (
r
cálculo directo )
- 10000 bucles, lo mejor de 3: 56,6 µs por bucle
- Scipy (regresión lineal con
r
como salida)
- 1000 bucles, lo mejor de 3: 676 µs por bucle
- Statsmodels (puede hacer polinomios de n-ésimo grado y muchos otros ajustes)
- 1000 bucles, lo mejor de 3: 422 µs por bucle
El método corrcoef supera por poco el cálculo de r ^ 2 "manualmente" utilizando métodos numerosos. Es> 5 veces más rápido que el método polyfit y ~ 12 veces más rápido que el scipy.linregress. Solo para reforzar lo que Numpy está haciendo por ti, es 28 veces más rápido que Python puro. No estoy muy versado en cosas como numba y pypy, por lo que alguien más tendría que llenar esos vacíos, pero creo que esto me convence bastante de que corrcoef
es la mejor herramienta para calcular r
una regresión lineal simple.
Aquí está mi código de evaluación comparativa. Copié y pegué de un Jupyter Notebook (es difícil no llamarlo un IPython Notebook ...), así que me disculpo si algo se rompió en el camino. El comando% timeit magic requiere 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_list)
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)