แต่เดิมฉันโพสต์เกณฑ์มาตรฐานด้านล่างโดยมีจุดประสงค์เพื่อแนะนำnumpy.corrcoef
โดยโง่เขลาที่ไม่ตระหนักว่าคำถามเดิมใช้อยู่แล้วcorrcoef
และในความเป็นจริงกำลังถามเกี่ยวกับความพอดีของพหุนามลำดับที่สูงกว่า ฉันได้เพิ่มวิธีแก้ปัญหาจริงให้กับคำถามพหุนาม r-squared โดยใช้ statsmodels และฉันได้ทิ้งเกณฑ์มาตรฐานเดิมซึ่งในขณะที่นอกหัวข้ออาจเป็นประโยชน์กับใครบางคน
statsmodels
มีความสามารถในการคำนวณr^2
พหุนามพอดีโดยตรงนี่คือ 2 วิธี ...
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
หากต้องการใช้ประโยชน์เพิ่มเติมstatsmodels
ควรดูที่ข้อมูลสรุปโมเดลที่ติดตั้งซึ่งสามารถพิมพ์หรือแสดงเป็นตาราง HTML ที่สมบูรณ์ในสมุดบันทึก Jupyter / IPython 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
นี่คือผลการจับเวลาของฉันจากการเปรียบเทียบวิธีการต่างๆสำหรับ 1,000 จุดสุ่ม (x, y):
- Pure Python (การ
r
คำนวณโดยตรง)
- 1,000 ลูปซึ่งดีที่สุดคือ 3: 1.59 ms ต่อลูป
- polyfit ที่เป็นก้อน (ใช้ได้กับพหุนามดีกรี n)
- 1,000 ลูปดีที่สุด 3: 3266s ต่อลูป
- Numpy Manual (
r
คำนวณโดยตรง)
- 10,000 ลูปดีที่สุด 3: 62.1 µs ต่อลูป
- Numpy corrcoef (
r
คำนวณโดยตรง)
- 10,000 ลูปดีที่สุด 3: 56.6.6s ต่อลูป
- Scipy (การถดถอยเชิงเส้นด้วย
r
เป็นเอาต์พุต)
- 1,000 ลูปดีที่สุด 3: 676 วินาทีต่อลูป
- Statsmodels (สามารถทำพหุนามระดับ n และอื่น ๆ อีกมากมาย)
- 1,000 ลูปดีที่สุด 3: 422 pers ต่อลูป
วิธี corrcoef เอาชนะการคำนวณ r ^ 2 "ด้วยตนเอง" ได้อย่างแคบโดยใช้วิธี numpy เร็วกว่าวิธี polyfit> 5 เท่าและเร็วกว่า scipy.linregress ~ 12 เท่า เพียงเพื่อเสริมสร้างสิ่งที่ numpy กำลังทำเพื่อคุณมันเร็วกว่า python บริสุทธิ์ 28 เท่า ฉันไม่ได้เชี่ยวชาญในสิ่งต่างๆเช่น numba และ pypy ดังนั้นคนอื่นจะต้องเติมช่องว่างเหล่านั้น แต่ฉันคิดว่านี่เป็นสิ่งที่น่าเชื่อสำหรับฉันมากว่าcorrcoef
เป็นเครื่องมือที่ดีที่สุดในการคำนวณr
การถดถอยเชิงเส้นอย่างง่าย
นี่คือรหัสเปรียบเทียบของฉัน ฉันคัดลอกมาจาก Jupyter Notebook (ยากที่จะไม่เรียกมันว่า IPython Notebook ... ) ดังนั้นฉันต้องขออภัยหากมีสิ่งใดขัดข้องระหว่างทาง คำสั่ง% 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_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)