我正在使用Python和Numpy来计算任意度数的最佳拟合多项式。我传递了一个x值,y值和我想要拟合的多项式的程度列表(线性,二次等)。
这很有用,但我也想计算r(相关系数)和r平方(确定系数)。我将我的结果与Excel的最佳拟合趋势线能力以及它计算的r平方值进行比较。使用这个,我知道我正在为线性最佳拟合(度等于1)正确计算r平方。但是,我的函数不适用于度数大于1的多项式。
Excel可以做到这一点。如何使用Numpy计算高阶多项式的r平方?
这是我的功能:
import numpy
# Polynomial Regression
def polyfit(x, y, degree):
results = {}
coeffs = numpy.polyfit(x, y, degree)
# Polynomial Coefficients
results['polynomial'] = coeffs.tolist()
correlation = numpy.corrcoef(x, y)[0,1]
# r
results['correlation'] = correlation
# r-squared
results['determination'] = correlation**2
return results
答案 0 :(得分:103)
一个非常晚的回复,但万一有人需要一个准备好的功能:
即
slope, intercept, r_value, p_value, std_err = scipy.stats.linregress(x, y)
在@Adam Marples的回答中。
答案 1 :(得分:52)
从numpy.polyfit文档中,它适合线性回归。具体而言,具有度'd'的numpy.polyfit适合具有均值函数的线性回归
E(y | x)= p_d * x ** d + p_ {d-1} * x **(d-1)+ ... + p_1 * x + p_0
所以你只需计算那个拟合的R平方。 linear regression上的维基百科页面提供了完整的详细信息。您对R ^ 2感兴趣,您可以通过几种方式计算,最简单的可能是
SST = Sum(i=1..n) (y_i - y_bar)^2
SSReg = Sum(i=1..n) (y_ihat - y_bar)^2
Rsquared = SSReg/SST
我使用'y_bar'表示y的平均值,'y_ihat'表示每个点的拟合值。
我对numpy(我通常在R中工作)并不十分熟悉,所以可能有更简洁的方法来计算你的R平方,但以下应该是正确的
import numpy
# Polynomial Regression
def polyfit(x, y, degree):
results = {}
coeffs = numpy.polyfit(x, y, degree)
# Polynomial Coefficients
results['polynomial'] = coeffs.tolist()
# r-squared
p = numpy.poly1d(coeffs)
# fit values, and mean
yhat = p(x) # or [p(z) for z in x]
ybar = numpy.sum(y)/len(y) # or sum(y)/len(y)
ssreg = numpy.sum((yhat-ybar)**2) # or sum([ (yihat - ybar)**2 for yihat in yhat])
sstot = numpy.sum((y - ybar)**2) # or sum([ (yi - ybar)**2 for yi in y])
results['determination'] = ssreg / sstot
return results
答案 2 :(得分:38)
来自yanl(还有另一个库)sklearn.metrics
有一个r2_square
函数;
from sklearn.metrics import r2_score
coefficient_of_dermination = r2_score(y, p(x))
答案 3 :(得分:19)
我一直在成功使用它,其中x和y类似于数组。
def rsquared(x, y):
""" Return R^2 where x and y are array-like."""
slope, intercept, r_value, p_value, std_err = scipy.stats.linregress(x, y)
return r_value**2
答案 4 :(得分:15)
我最初发布下面的基准是为了推荐numpy.corrcoef
,愚蠢地没有意识到原始问题已经使用corrcoef
并且实际上是在询问更高阶多项式拟合。我已经使用statsmodels为多项式r-squared问题添加了一个实际的解决方案,并且我已经离开了原始的基准测试,这些基准测试虽然偏离主题,但对某些人来说可能是有用的。
statsmodels
能够直接计算多项式拟合的r^2
,这里有两种方法......
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
为了进一步利用statsmodels
,还应该查看拟合的模型摘要,该摘要可以在Jupyter / IPython笔记本中打印或显示为丰富的HTML表格。除了rsquared
之外,结果对象还提供对许多有用的统计指标的访问。
model = sm.OLS(y, xpoly)
results = model.fit()
results.summary()
以下是我的原始答案,其中我对各种线性回归r ^ 2方法进行了基准测试...
问题中使用的corrcoef函数仅针对单个线性回归计算相关系数r
,因此它不能解决高阶多项式r^2
的问题适合。然而,对于它的价值,我发现对于线性回归,它确实是计算r
的最快和最直接的方法。
def get_r2_numpy_corrcoef(x, y):
return np.corrcoef(x, y)[0, 1]**2
这是我通过比较1000个随机(x,y)点的一系列方法得出的时间结果:
r
计算)
r
计算)
r
计算)
r
为输出的线性回归)
corrcoef方法使用numpy方法以“手动”方式勉强计算r ^ 2。它比polyfit方法快5倍,比scipy.linregress快约12倍。只是为了加强numpy为你做的事情,它比纯蟒蛇快28倍。我不熟悉像numba和pypy这样的东西,所以其他人不得不填补这些空白,但我认为我很有说服力corrcoef
是计算r
的最佳工具用于简单的线性回归。
这是我的基准测试代码。我从Jupyter笔记本上复制粘贴(很难不称它为IPython笔记本......),所以如果有什么事情发生,我道歉。 %timeit magic命令需要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)
答案 5 :(得分:5)
关于r-squareds的维基百科文章表明它可能用于一般模型拟合而不仅仅是线性回归。
答案 6 :(得分:4)
R平方是一个仅适用于线性回归的统计量。
基本上,它衡量的是数据的变化可以用线性回归来解释。
因此,您计算“平方总和”,即每个结果变量与平均值的总平方偏差。 。
\ sum_ {i}(y_ {i} - y_bar)^ 2
其中y_bar是y的平均值。
然后,你计算“回归平方和”,即你的FITTED值与平均值的差异
\ sum_ {i}(yHat_ {i} - y_bar)^ 2
找到这两者的比例。
现在,你需要做的多项式拟合就是从该模型中插入y_hat,但是调用r平方并不准确。
Here是我发现的一个链接。
答案 7 :(得分:4)
这是一个用Python和Numpy计算加权 r平方的函数(大部分代码来自sklearn):
from __future__ import division
import numpy as np
def compute_r2_weighted(y_true, y_pred, weight):
sse = (weight * (y_true - y_pred) ** 2).sum(axis=0, dtype=np.float64)
tse = (weight * (y_true - np.average(
y_true, axis=0, weights=weight)) ** 2).sum(axis=0, dtype=np.float64)
r2_score = 1 - (sse / tse)
return r2_score, sse, tse
示例:
from __future__ import print_function, division
import sklearn.metrics
def compute_r2_weighted(y_true, y_pred, weight):
sse = (weight * (y_true - y_pred) ** 2).sum(axis=0, dtype=np.float64)
tse = (weight * (y_true - np.average(
y_true, axis=0, weights=weight)) ** 2).sum(axis=0, dtype=np.float64)
r2_score = 1 - (sse / tse)
return r2_score, sse, tse
def compute_r2(y_true, y_predicted):
sse = sum((y_true - y_predicted)**2)
tse = (len(y_true) - 1) * np.var(y_true, ddof=1)
r2_score = 1 - (sse / tse)
return r2_score, sse, tse
def main():
'''
Demonstrate the use of compute_r2_weighted() and checks the results against sklearn
'''
y_true = [3, -0.5, 2, 7]
y_pred = [2.5, 0.0, 2, 8]
weight = [1, 5, 1, 2]
r2_score = sklearn.metrics.r2_score(y_true, y_pred)
print('r2_score: {0}'.format(r2_score))
r2_score,_,_ = compute_r2(np.array(y_true), np.array(y_pred))
print('r2_score: {0}'.format(r2_score))
r2_score = sklearn.metrics.r2_score(y_true, y_pred,weight)
print('r2_score weighted: {0}'.format(r2_score))
r2_score,_,_ = compute_r2_weighted(np.array(y_true), np.array(y_pred), np.array(weight))
print('r2_score weighted: {0}'.format(r2_score))
if __name__ == "__main__":
main()
#cProfile.run('main()') # if you want to do some profiling
输出:
r2_score: 0.9486081370449679
r2_score: 0.9486081370449679
r2_score weighted: 0.9573170731707317
r2_score weighted: 0.9573170731707317
f_i是拟合的预测值,y_ {av}是观测数据的平均值y_i是观测数据值。 w_i是应用于每个数据点的权重,通常为w_i = 1。 SSE是由于误差引起的平方和,SST是平方的总和。
如果有兴趣,R中的代码:https://gist.github.com/dhimmel/588d64a73fa4fef02c8f(mirror)
答案 8 :(得分:2)
这是一个非常简单的python函数,它假设y和y_hat为熊猫系列,根据实际值和预测值计算R ^ 2:
def r_squared(y, y_hat):
y_bar = y.mean()
ss_tot = ((y-y_bar)**2).sum()
ss_res = ((y-y_hat)**2).sum()
return 1 - (ss_res/ss_tot)
答案 9 :(得分:0)
来自scipy.stats.linregress源。他们使用平均平方和法。
import numpy as np
x = np.array(x)
y = np.array(y)
# average sum of squares:
ssxm, ssxym, ssyxm, ssym = np.cov(x, y, bias=1).flat
r_num = ssxym
r_den = np.sqrt(ssxm * ssym)
r = r_num / r_den
if r_den == 0.0:
r = 0.0
else:
r = r_num / r_den
if r > 1.0:
r = 1.0
elif r < -1.0:
r = -1.0
答案 10 :(得分:0)
您可以直接执行此代码,这将为您找到多项式,并为您找到R值。如果您需要更多说明,可以在下面添加注释。
from scipy.stats import linregress
import numpy as np
x = np.array([1,2,3,4,5,6])
y = np.array([2,3,5,6,7,8])
p3 = np.polyfit(x,y,3) # 3rd degree polynomial, you can change it to any degree you want
xp = np.linspace(1,6,6) # 6 means the length of the line
poly_arr = np.polyval(p3,xp)
poly_list = [round(num, 3) for num in list(poly_arr)]
slope, intercept, r_value, p_value, std_err = linregress(x, poly_list)
print(r_value**2)