Eu originalmente postei os benchmarks abaixo com o propósito de recomendar numpy.corrcoef
, tolamente não percebendo que a pergunta original já usa corrcoef
e, na verdade, estava perguntando sobre ajustes polinomiais de ordem superior. Eu adicionei uma solução real para a questão polinomial r-quadrado usando modelos de estatísticas e deixei os benchmarks originais, que embora fora do tópico, são potencialmente úteis para alguém.
statsmodels
tem a capacidade de calcular o r^2
de um ajuste polinomial diretamente, aqui estão 2 métodos ...
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
Para aproveitar ainda mais statsmodels
, deve-se também olhar o resumo do modelo ajustado, que pode ser impresso ou exibido como uma rica tabela HTML no bloco de notas Jupyter / IPython. O objeto de resultados fornece acesso a muitas métricas estatísticas úteis, além de rsquared
.
model = sm.OLS(y, xpoly)
results = model.fit()
results.summary()
Abaixo está minha resposta original, onde comparei vários métodos de regressão linear r ^ 2 ...
A função corrcoef usada na pergunta calcula o coeficiente de correlação ,,r
apenas para uma única regressão linear, portanto, não aborda a questão de r^2
para ajustes polinomiais de ordem superior. No entanto, pelo que vale a pena, descobri que, para a regressão linear, é de fato o método de cálculo mais rápido e direto r
.
def get_r2_numpy_corrcoef(x, y):
return np.corrcoef(x, y)[0, 1]**2
Estes foram os meus resultados timeit comparando um monte de métodos para 1000 pontos aleatórios (x, y):
- Python puro (
r
cálculo direto )
- 1000 loops, melhor de 3: 1,59 ms por loop
- Numpy polyfit (aplicável a ajustes polinomiais de n-ésimo grau)
- 1000 loops, melhor de 3: 326 µs por loop
- Numpy Manual (
r
cálculo direto )
- 10.000 loops, melhor de 3: 62,1 µs por loop
- Numpy corrcoef (
r
cálculo direto )
- 10.000 loops, melhor de 3: 56,6 µs por loop
- Scipy (regressão linear com
r
saída)
- 1000 loops, melhor de 3: 676 µs por loop
- Modelos de estatísticas (podem fazer polinômios de n-ésimo grau e muitos outros ajustes)
- 1000 loops, melhor de 3: 422 µs por loop
O método corrcoef supera o cálculo de r ^ 2 "manualmente" usando métodos numpy. É> 5X mais rápido do que o método polyfit e ~ 12X mais rápido do que o scipy.linregress. Apenas para reforçar o que o numpy está fazendo por você, ele é 28 vezes mais rápido do que o python puro. Não sou muito versado em coisas como numba e pypy, então outra pessoa teria que preencher essas lacunas, mas acho que isso é muito convincente para mim que corrcoef
é a melhor ferramenta para calcular r
uma regressão linear simples.
Aqui está o meu código de benchmarking. Copiei e colei de um Notebook Jupyter (difícil não chamá-lo de Notebook IPython ...), então peço desculpas se alguma coisa quebrou no caminho. O comando mágico% timeit requer 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)