J'ai initialement publié les points de repère ci-dessous dans le but de recommander numpy.corrcoef
, stupidement ne me rendant pas compte que la question d'origine utilise déjà corrcoef
et posait en fait des questions sur les ajustements polynomiaux d'ordre supérieur. J'ai ajouté une solution réelle à la question polynomiale r-carré à l'aide de statsmodels, et j'ai laissé les repères d'origine, qui, bien que hors sujet, sont potentiellement utiles à quelqu'un.
statsmodels
a la capacité de calculer r^2
directement l'ajustement polynomial, voici 2 méthodes ...
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
Pour en tirer davantage parti statsmodels
, il convient également de consulter le résumé du modèle ajusté, qui peut être imprimé ou affiché sous forme de tableau HTML riche dans le notebook Jupyter / IPython. L'objet de résultats donne accès à de nombreuses mesures statistiques utiles en plus de rsquared
.
model = sm.OLS(y, xpoly)
results = model.fit()
results.summary()
Voici ma réponse originale où j'ai comparé diverses méthodes de régression linéaire r ^ 2 ...
La fonction corrcoef utilisée dans la Question calcule le coefficient de corrélation r
, uniquement pour une seule régression linéaire, elle ne répond donc pas à la question des r^2
ajustements polynomiaux d'ordre supérieur. Cependant, pour ce que cela vaut, j'en suis venu à trouver que pour la régression linéaire, c'est en effet la méthode de calcul la plus rapide et la plus directe r
.
def get_r2_numpy_corrcoef(x, y):
return np.corrcoef(x, y)[0, 1]**2
Ce sont mes résultats timeit en comparant un tas de méthodes pour 1000 points aléatoires (x, y):
- Python pur (
r
calcul direct )
- 1000 boucles, meilleur de 3: 1,59 ms par boucle
- Numpy polyfit (applicable aux ajustements polynomiaux au n-ième degré)
- 1000 boucles, meilleur de 3: 326 µs par boucle
- Manuel Numpy (
r
calcul direct )
- 10000 boucles, meilleur de 3: 62,1 µs par boucle
- Numpy corrcoef (
r
calcul direct )
- 10000 boucles, meilleur de 3: 56,6 µs par boucle
- Scipy (régression linéaire avec
r
comme sortie)
- 1000 boucles, meilleur de 3: 676 µs par boucle
- Statsmodels (peut faire des polynômes au n-ième degré et de nombreux autres ajustements)
- 1000 boucles, meilleur de 3: 422 µs par boucle
La méthode corrcoef bat étroitement le calcul du r ^ 2 "manuellement" en utilisant les méthodes numpy. Il est> 5 fois plus rapide que la méthode polyfit et ~ 12 fois plus rapide que scipy.linregress. Juste pour renforcer ce que numpy fait pour vous, il est 28 fois plus rapide que le python pur. Je ne connais pas bien des choses comme numba et pypy, donc quelqu'un d'autre devrait combler ces lacunes, mais je pense que c'est très convaincant pour moi que corrcoef
c'est le meilleur outil pour calculer r
une simple régression linéaire.
Voici mon code d'analyse comparative. J'ai copié-collé à partir d'un notebook Jupyter (difficile de ne pas l'appeler un notebook IPython ...), alors je m'excuse si quelque chose s'est cassé en cours de route. La commande% timeit magic nécessite 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)