Làm cách nào để tính toán bình phương r bằng Python và Numpy?


92

Tôi đang sử dụng Python và Numpy để tính toán đa thức phù hợp nhất với mức độ tùy ý. Tôi chuyển danh sách các giá trị x, giá trị y và bậc của đa thức tôi muốn khớp (tuyến tính, bậc hai, v.v.).

Điều này nhiều hiệu quả, nhưng tôi cũng muốn tính toán r (hệ số tương quan) và r-bình phương (hệ số xác định). Tôi đang so sánh kết quả của mình với khả năng đường xu hướng phù hợp nhất của Excel và giá trị bình phương r mà nó tính toán. Sử dụng điều này, tôi biết tôi đang tính toán r bình phương một cách chính xác cho phù hợp nhất tuyến tính (độ bằng 1). Tuy nhiên, hàm của tôi không hoạt động đối với đa thức có bậc lớn hơn 1.

Excel có thể làm điều này. Làm cách nào để tính toán r bình phương cho các đa thức bậc cao hơn bằng cách sử dụng Numpy?

Đây là chức năng của tôi:

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

1
Lưu ý: bạn chỉ sử dụng mức độ trong việc tính toán các hệ số.
Nick Dandoulakis

tydok là chính xác. Bạn đang tính toán mối tương quan của x và y và r bình phương cho y = p_0 + p_1 * x. Xem câu trả lời của tôi bên dưới để biết một số mã sẽ hoạt động. Nếu bạn không phiền tôi hỏi, mục tiêu cuối cùng của bạn là gì? Bạn đang thực hiện lựa chọn mô hình (chọn mức độ nào để sử dụng)? Hay cái gì khác?
leif

@leif - Yêu cầu tổng hợp thành "làm như Excel làm". Tôi có cảm giác từ những câu trả lời này rằng người dùng có thể đang đọc quá nhiều vào giá trị r bình phương khi sử dụng đường cong phù hợp nhất phi tuyến tính. Tuy nhiên, tôi không phải là một thuật sĩ toán học và đây là chức năng được yêu cầu.
Travis Beale

Câu trả lời:


62

Từ tài liệu numpy.polyfit , nó phù hợp với hồi quy tuyến tính. Cụ thể, numpy.polyfit với độ 'd' phù hợp với một hồi quy tuyến tính với hàm trung bình

E (y | x) = p_d * x ** d + p_ {d-1} * x ** (d-1) + ... + p_1 * x + p_0

Vì vậy, bạn chỉ cần tính R bình phương cho phù hợp đó. Trang wikipedia về hồi quy tuyến tính cung cấp đầy đủ chi tiết. Bạn quan tâm đến R ^ 2 mà bạn có thể tính toán theo một số cách, cách dễ nhất có lẽ là

SST = Sum(i=1..n) (y_i - y_bar)^2
SSReg = Sum(i=1..n) (y_ihat - y_bar)^2
Rsquared = SSReg/SST

Trong đó tôi sử dụng 'y_bar' cho giá trị trung bình của y và 'y_ihat' là giá trị phù hợp cho mỗi điểm.

Tôi không quen lắm với numpy (tôi thường làm việc với R), vì vậy có lẽ có một cách gọn gàng hơn để tính bình phương R của bạn, nhưng điều sau đây sẽ chính xác

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

5
Tôi chỉ muốn chỉ ra rằng việc sử dụng các chức năng mảng NumPy thay vì danh sách hiểu sẽ nhanh hơn nhiều, ví dụ như numpy.sum ((yi - ybar) ** 2) và dễ dàng hơn để đọc
Josef

17
Theo trang wiki en.wikipedia.org/wiki/Coenough_of_determination , định nghĩa chung nhất về R ^ 2 R^2 = 1 - SS_err/SS_tot, R^2 = SS_reg/SS_totchỉ là một trường hợp đặc biệt.
LWZ

137

Một câu trả lời rất muộn, nhưng đề phòng ai đó cần một chức năng sẵn sàng cho việc này:

scipy.stats.linregress

I E

slope, intercept, r_value, p_value, std_err = scipy.stats.linregress(x, y)

như trong câu trả lời của @Adam Marples.


Phân tích bằng hệ số tương quan và sau đó thực hiện công việc lớn hơn là hồi quy .
象 嘉 道

19
Trả lời này chỉ hoạt động cho hồi quy tuyến tính, đó là đa thức hồi quy đơn giản nhất
tashuhka

8
Thận trọng: r_value ở đây là hệ số tương quan của Pearson, không phải R bình phương. r_squared = r_value ** 2
Vladimir Lukin

52

Từ yanl (yet-another-library) sklearn.metricscó một r2_scorehàm;

from sklearn.metrics import r2_score

coefficient_of_dermination = r2_score(y, p(x))

1
(Cẩn thận: "Giá trị mặc định tương ứng với 'variance_weighted', hành vi này bị phản đối kể từ phiên bản 0,17 và sẽ được thay đổi để 'uniform_average' bắt đầu từ 0.19")
Franck Dernoncourt

4
r2_score trong sklearn có thể là giá trị âm, đây không phải là trường hợp bình thường.
Qinqing Liu,

1
Tại sao r2_score([1,2,3],[4,5,7])= -16?
cz

22

Tôi đã sử dụng điều này thành công, trong đó x và y giống như mảng.

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

20

Ban đầu tôi đăng các điểm chuẩn bên dưới với mục đích khuyến nghị numpy.corrcoef, thật ngu ngốc khi không nhận ra rằng câu hỏi ban đầu đã sử dụng corrcoefvà trên thực tế đang hỏi về các khớp đa thức bậc cao. Tôi đã thêm một giải pháp thực tế cho câu hỏi bình phương r đa thức bằng cách sử dụng mô hình thống kê và tôi đã để lại các điểm chuẩn ban đầu, mặc dù lạc đề, nhưng có khả năng hữu ích cho ai đó.


statsmodelscó khả năng tính toán r^2phù hợp đa thức trực tiếp, đây là 2 phương pháp ...

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

Để tận dụng lợi thế hơn nữa statsmodels, người ta cũng nên xem bản tóm tắt mô hình được trang bị, có thể được in hoặc hiển thị dưới dạng bảng HTML phong phú trong sổ ghi chép Jupyter / IPython. Ngoài ra, đối tượng kết quả cung cấp quyền truy cập vào nhiều chỉ số thống kê hữu ích rsquared.

model = sm.OLS(y, xpoly)
results = model.fit()
results.summary()

Dưới đây là Câu trả lời ban đầu của tôi, nơi tôi đã chuẩn hóa các phương pháp hồi quy tuyến tính r ^ 2 khác nhau ...

Hàm corrcoef được sử dụng trong Câu hỏi tính toán hệ số tương quan r, chỉ cho một hồi quy tuyến tính duy nhất, do đó, nó không giải quyết câu hỏi về các r^2khớp đa thức bậc cao. Tuy nhiên, đối với giá trị của nó, tôi nhận thấy rằng đối với hồi quy tuyến tính, nó thực sự là phương pháp tính toán nhanh nhất và trực tiếp nhất r.

def get_r2_numpy_corrcoef(x, y):
    return np.corrcoef(x, y)[0, 1]**2

Đây là kết quả thời gian của tôi từ việc so sánh một loạt các phương pháp cho 1000 điểm ngẫu nhiên (x, y):

  • Python thuần túy ( rtính toán trực tiếp )
    • 1000 vòng, tốt nhất là 3: 1,59 ms mỗi vòng
  • Numpy polyfit (áp dụng cho các khớp đa thức bậc n)
    • 1000 vòng, tốt nhất là 3: 326 µs mỗi vòng
  • Numpy Manual ( rtính toán trực tiếp )
    • 10000 vòng, tốt nhất là 3: 62,1 µs mỗi vòng
  • Numpy corrcoef ( rtính toán trực tiếp )
    • 10000 vòng, tốt nhất là 3: 56,6 µs mỗi vòng
  • Scipy (hồi quy tuyến tính với rdưới dạng đầu ra)
    • 1000 vòng, tốt nhất là 3: 676 µs mỗi vòng
  • Statsmodels (có thể làm đa thức bậc n và nhiều kiểu phù hợp khác)
    • 1000 vòng lặp, tốt nhất là 3: 422 µs mỗi vòng lặp

Phương pháp corrcoef gần như đánh bại việc tính toán r ^ 2 "theo cách thủ công" bằng phương pháp numpy. Nó nhanh hơn> 5 lần so với phương pháp polyfit và nhanh hơn ~ 12 lần so với scipy.linregress. Chỉ để củng cố những gì numpy đang làm cho bạn, nó nhanh hơn 28 lần so với python thuần túy. Tôi không thành thạo về những thứ như numba và pypy, vì vậy người khác sẽ phải lấp đầy những khoảng trống đó, nhưng tôi nghĩ rằng điều này rất thuyết phục đối với tôi đó corrcoeflà công cụ tốt nhất để tính toán rcho một hồi quy tuyến tính đơn giản.

Đây là mã điểm chuẩn của tôi. Tôi đã sao chép từ Máy tính xách tay Jupyter (khó có thể gọi nó là Máy tính xách tay IPython ...), vì vậy tôi xin lỗi nếu có bất kỳ điều gì bị hỏng trên đường đi. Lệnh ma thuật% timeit yêu cầu 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)

1
Bạn đang so sánh 3 phương pháp có lắp độ dốc và hồi quy với 3 phương pháp không lắp độ dốc.
Josef

Vâng, tôi biết điều đó nhiều ... nhưng bây giờ tôi cảm thấy ngớ ngẩn vì không đọc câu hỏi ban đầu và thấy rằng nó đã sử dụng corrcoef và đang giải quyết cụ thể r ^ 2 cho các đa thức bậc cao ... bây giờ tôi cảm thấy ngớ ngẩn khi đăng điểm chuẩn của mình. cho một mục đích khác. Rất tiếc ...
bellfreak7

1
Tôi đã cập nhật câu trả lời của mình với một giải pháp cho câu hỏi ban đầu bằng cách sử dụng statsmodelsvà xin lỗi vì điểm chuẩn không cần thiết của các phương pháp hồi quy tuyến tính r ^ 2, mà tôi giữ là thông tin thú vị nhưng lạc đề.
flanfreak7

Tôi vẫn thấy điểm chuẩn thú vị vì tôi không mong đợi tốc độ truy cập của scipy sẽ chậm hơn so với các mô hình thống kê hoạt động chung chung hơn.
Josef

1
Lưu ý, np.column_stack([x**i for i in range(k+1)])có thể được vectơ hóa trong numpy với x[:,None]**np.arange(k+1)hoặc sử dụng các hàm vander của numpy có thứ tự đảo ngược trong các cột.
Josef

5

R bình phương là một thống kê chỉ áp dụng cho hồi quy tuyến tính.

Về cơ bản, nó đo lường mức độ thay đổi trong dữ liệu của bạn có thể được giải thích bằng hồi quy tuyến tính.

Vì vậy, bạn tính toán "Tổng bình phương", là tổng bình phương độ lệch của mỗi biến kết quả của bạn so với giá trị trung bình của chúng. . .

\ sum_ {i} (y_ {i} - y_bar) ^ 2

trong đó y_bar là giá trị trung bình của y.

Sau đó, bạn tính toán "tổng hồi quy của các bình phương", là giá trị FITTED của bạn khác với giá trị trung bình là bao nhiêu

\ sum_ {i} (yHat_ {i} - y_bar) ^ 2

và tìm tỉ số của hai số đó.

Bây giờ, tất cả những gì bạn phải làm để phù hợp với đa thức là cắm y_hat's từ mô hình đó, nhưng không chính xác khi gọi đó là r-squared.

Đây là một liên kết mà tôi tìm thấy nói lên nó một chút.


Đây dường như là gốc rễ của vấn đề của tôi. Làm thế nào để Excel nhận được một giá trị bình phương r khác cho một đa thức phù hợp với một hồi quy tuyến tính sau đó?
Travis Beale

1
bạn chỉ cung cấp cho excel các khớp từ một hồi quy tuyến tính và các khớp từ một mô hình đa thức? Nó sẽ tính toán rsq từ hai mảng dữ liệu và chỉ cần giả sử rằng bạn đang cho nó phù hợp với mô hình tuyến tính. Bạn đang cho excel gì? Lệnh 'đường xu hướng phù hợp nhất' trong excel là gì?
Baltimark

Nó là một phần của các hàm vẽ đồ thị của Excel. Bạn có thể vẽ một số dữ liệu, nhấp chuột phải vào nó, sau đó chọn từ một số loại đường xu hướng khác nhau. Có tùy chọn để xem phương trình của đường cũng như giá trị bình phương r cho mỗi loại. Giá trị bình phương r cũng khác nhau đối với từng loại.
Travis Beale

@Travis Beale - bạn sẽ nhận được một bình phương r khác nhau cho mỗi hàm trung bình khác nhau mà bạn thử (trừ khi hai mô hình được lồng vào nhau và các hệ số phụ trong mô hình lớn hơn đều bằng 0). Vì vậy, tất nhiên Excel cung cấp một giá trị r bình phương khác nhau. @Baltimark - đây là hồi quy tuyến tính nên nó là bình phương r.
leif


5

Đây là một hàm để tính toán bình phương r có trọng số với Python và Numpy (hầu hết mã đến từ 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

Thí dụ:

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

kết quả đầu ra:

r2_score: 0.9486081370449679
r2_score: 0.9486081370449679
r2_score weighted: 0.9573170731707317
r2_score weighted: 0.9573170731707317

Điều này tương ứng với công thức ( mirror ):

nhập mô tả hình ảnh ở đây

với f_i là giá trị dự đoán từ sự phù hợp, y_ {av} là giá trị trung bình của dữ liệu quan sát được y_i là giá trị dữ liệu quan sát. w_i là trọng số được áp dụng cho mỗi điểm dữ liệu, thường w_i = 1. SSE là tổng bình phương do lỗi và SST là tổng bình phương.


Nếu quan tâm, mã trong R: https://gist.github.com/dhimmel/588d64a73fa4fef02c8f ( mirror )


2

Đây là một hàm python rất đơn giản để tính R ^ 2 từ các giá trị thực tế và dự đoán giả sử y và y_hat là chuỗi gấu trúc:

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)

0

Từ nguồn scipy.stats.linregress. Họ sử dụng phương pháp tổng bình phương trung bình.

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

0

Bạn có thể thực thi mã này trực tiếp, mã này sẽ tìm cho bạn đa thức và sẽ tìm cho bạn giá trị R, bạn có thể đặt bình luận xuống bên dưới nếu bạn cần giải thích thêm.

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)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.