Python ve Numpy kullanarak r-kare'yi nasıl hesaplarım?


92

Python ve Numpy'yi rasgele dereceye en uygun polinomu hesaplamak için kullanıyorum. X değerleri, y değerleri ve sığdırmak istediğim polinomun derecesini (doğrusal, ikinci dereceden, vb.) İçeren bir liste geçiriyorum.

Bu çok işe yarıyor, ancak aynı zamanda r (korelasyon katsayısı) ve r-kare (belirleme katsayısı) hesaplamak istiyorum. Sonuçlarımı Excel'in en uygun eğilim çizgisi özelliği ve hesapladığı r kare değeriyle karşılaştırıyorum. Bunu kullanarak, doğrusal en uygunluk için r-kareyi doğru hesapladığımı biliyorum (derece 1'e eşittir). Bununla birlikte, fonksiyonum 1'den büyük dereceye sahip polinomlar için çalışmıyor.

Excel bunu yapabilir. Numpy kullanarak daha yüksek dereceden polinomlar için r-kareyi nasıl hesaplarım?

İşte benim fonksiyonum:

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
Not: Dereceyi yalnızca katsayı hesaplamasında kullanırsınız.
Nick Dandoulakis

tydok doğru. X ve y korelasyonunu ve y = p_0 + p_1 * x için r-kare'yi hesaplıyorsunuz. Çalışması gereken bazı kodlar için aşağıdaki cevabıma bakın. Sormamın sakıncası yoksa, nihai hedefin nedir? Model seçimi yapıyor musunuz (ne derece kullanacağınızı seçerek)? Veya başka bir şey?
leif

@leif - İstek, "Excel'in yaptığı gibi yap" şeklinde özetlenir. Bu yanıtlardan, doğrusal olmayan bir en uygun eğri kullanırken kullanıcıların r kare değerini çok fazla okuyor olabileceği hissine kapılıyorum. Yine de, ben bir matematik sihirbazı değilim ve istenen işlev budur.
Travis Beale

Yanıtlar:


62

Gönderen numpy.polyfit belgelerinde, bu lineer regresyon uydurma olduğunu. Spesifik olarak, 'd' dereceli numpy.polyfit, ortalama fonksiyonla doğrusal bir regresyona uyar

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

Yani bu uyum için sadece R-karesini hesaplamanız gerekiyor. Doğrusal regresyondaki wikipedia sayfası tüm ayrıntıları verir. Birkaç şekilde hesaplayabileceğiniz R ^ 2 ile ilgileniyorsunuz, muhtemelen en kolayı

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

Y'lerin ortalaması için 'y_bar' ve her nokta için uygun değer olarak 'y_ihat' kullandığım yerde.

Numpy'ye çok aşina değilim (genellikle R'de çalışırım), bu yüzden muhtemelen R-karenizi hesaplamanın daha düzenli bir yolu vardır, ancak aşağıdaki doğru olmalıdı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

5
Liste anlama yerine numpy dizi işlevlerini kullanmanın çok daha hızlı olacağını, örneğin numpy.sum ((yi - ybar) ** 2) ve okuması daha kolay olacağını belirtmek isterim
Josef

17
Wiki sayfası göre en.wikipedia.org/wiki/Coefficient_of_determination R ^ 2 en genel tanımıdır R^2 = 1 - SS_err/SS_totile R^2 = SS_reg/SS_totsadece özel bir durum olmaktan.
LWZ

137

Çok geç bir cevap, ancak birisinin bunun için hazır bir işleve ihtiyaç duyması durumunda:

scipy.stats.linregress

yani

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

@Adam Marples'ın cevabında olduğu gibi.


Korelasyon katsayısı ile analiz etmek ve ardından daha büyük iş olan regresyonu yapmak mantıklıdır .
象 嘉 道

19
Bu yanıt yalnızca en basit polinom regresyonu olan doğrusal regresyon için işe
yarar

9
Dikkat: burada r_value, R-kare değil, Pearson korelasyon katsayısıdır. r_squared = r_value ** 2
Vladimir Lukin

52

Yanl'dan (henüz-başka-kitaplık) sklearn.metricsbir r2_scoreişlevi vardır;

from sklearn.metrics import r2_score

coefficient_of_dermination = r2_score(y, p(x))

1
(Dikkat: "Varsayılan değer 'varyans_ağırlıklı' değerine karşılık gelir, bu davranış sürüm 0.17'den beri kullanımdan kaldırılmıştır ve 0.19'dan başlayarak 'uniform_average' olarak değiştirilecektir")
Franck Dernoncourt

4
sklearn'deki r2_score negatif bir değer olabilir, bu normal durum değildir.
Qinqing Liu

1
Neden r2_score([1,2,3],[4,5,7])= -16?
cz

22

Bunu başarıyla kullanıyorum, burada x ve y dizi benzeri.

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

Başlangıçta aşağıdaki kriterleri tavsiye etmek amacıyla yayınladım numpy.corrcoef, aptalca orijinal sorunun halihazırda kullandığını corrcoefve aslında daha yüksek dereceden polinom uyumu sorduğunun farkında değildim . İstatistik modellerini kullanarak polinom r-kare sorusuna gerçek bir çözüm ekledim ve konu dışı olsa da potansiyel olarak birileri için yararlı olan orijinal kriterleri bıraktım.


statsmodelsr^2doğrudan bir polinom uyumu hesaplama yeteneğine sahiptir , işte 2 yöntem ...

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

Bundan daha fazla yararlanmak için statsmodels, Jupyter / IPython not defterinde zengin bir HTML tablosu olarak yazdırılabilen veya görüntülenebilen uygun model özetine de bakılmalıdır. Sonuçlar nesnesi, birçok yararlı istatistiksel ölçüme ek olarak erişim sağlar rsquared.

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

Aşağıda, çeşitli doğrusal regresyon r ^ 2 yöntemlerini karşılaştırdığım orijinal Cevabım var ...

Corrcoef Soru kullanılan fonksiyon korelasyon katsayısı, hesaplar r, yalnızca tek bir doğrusal regresyon için, bu yüzden sorusunu ele almaz r^2yüksek mertebeden çokterimli için. Bununla birlikte, ne olursa olsun, doğrusal regresyon için bunun gerçekten de en hızlı ve en doğrudan hesaplama yöntemi olduğunu buldum r.

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

Bunlar benim zamanımdıBir grup yöntemi 1000 rastgele (x, y) nokta için karşılaştırmanın sonuçları:

  • Saf Python (doğrudan rhesaplama)
    • 1000 döngü, döngü başına en iyi 3: 1,59 ms
  • Numpy polyfit (n-inci derece polinom uyumu için geçerlidir)
    • 1000 döngü, döngü başına en iyi 3: 326 µs
  • Numpy Kılavuzu (doğrudan rhesaplama)
    • 10000 döngü, döngü başına en iyi 3: 62,1 µs
  • Numpy corrcoef (doğrudan rhesaplama)
    • 10000 döngü, döngü başına en iyi 3: 56,6 µs
  • Scipy ( rçıktı olarak doğrusal regresyon )
    • 1000 döngü, döngü başına en iyi 3: 676 µs
  • İstatistik modelleri (n. Derece polinom ve diğer birçok uyumu yapabilir)
    • 1000 döngü, döngü başına en iyi 3: 422 µs

Corrcoef yöntemi, numpy yöntemlerini kullanarak "elle" r ^ 2 hesaplamasını dar bir şekilde yener. Polyfit yönteminden> 5X ve scipy.linregress'ten ~ 12X daha hızlıdır. Sadece numpy'nin sizin için ne yaptığını pekiştirmek için, saf python'dan 28 kat daha hızlı. Numba ve pypy gibi konularda çok bilgili değilim, bu yüzden başka birinin bu boşlukları doldurması gerekecekti, ama bence bu, basit bir doğrusal regresyon corrcoefiçin hesaplama yapmak riçin en iyi araç olduğunun bana çok ikna edici olduğunu düşünüyorum .

İşte kıyaslama kodum. Bir Jupyter Not Defterinden kopyalayıp yapıştırdım (buna IPython Defter dememek zor ...), bu yüzden yolda bir sorun olursa özür dilerim. % Timeit sihirli komutu IPython gerektirir.

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
Eğim uydurma ile 3 yöntemi, eğim uydurmadan 3 yöntemle karşılaştırıyorsunuz.
Josef

Evet, çok şey biliyordum ... ama şimdi orijinal soruyu okumadığım ve onun halihazırda düzeltme kullandığını ve özellikle daha yüksek dereceli polinomlar için r ^ 2'ye hitap ettiğini gördüğüm için aptal hissediyorum ... şimdi kıyaslamalarımı yayınladığım için aptal hissediyorum farklı bir amaç içindi. Hata ...
flutefreak7

1
Cevabımı orijinal soruya bir çözümle güncelledim statsmodelsve ilginç ama konu dışı bilgi olarak sakladığım doğrusal regresyon r ^ 2 yöntemlerinin gereksiz kıyaslaması için özür diledim.
flutefreak7

Ben yine de kıyaslamayı ilginç buluyorum çünkü scipy'nin çizgisel gelişiminin, daha genel işler yapan istatistik modellerinden daha yavaş olmasını beklemiyordum.
Josef

1
Not, sütunlardaki sırası tersine çevrilmiş numpy'nin vander işlevleri np.column_stack([x**i for i in range(k+1)])ile x[:,None]**np.arange(k+1)veya kullanılarak numpy olarak vektörleştirilebilir .
Josef

5

R-kare, yalnızca doğrusal regresyon için geçerli olan bir istatistiktir.

Esasen, verilerinizdeki ne kadar varyasyonun doğrusal regresyonla açıklanabileceğini ölçer.

Böylece, sonuç değişkenlerinizin her birinin ortalamalarından toplam kare sapması olan "Toplam Kareler Toplamı" nı hesaplarsınız. . .

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

burada y_bar, y'lerin ortalamasıdır.

Ardından, "karelerin regresyon toplamını" hesaplarsınız; bu, FITTED değerlerinin ortalamadan ne kadar farklı olduğunu gösterir.

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

ve bu ikisinin oranını bulun.

Şimdi, bir polinom uydurma için yapmanız gereken tek şey, o modeldeki y_hat'leri takmaktır, ancak bunu r-kare olarak adlandırmak doğru değildir.

İşte ona biraz konuşan bulduğum bir bağlantı.


Sorunumun kökü bu gibi görünüyor. O halde Excel, bir polinom uyumu için doğrusal bir regresyona karşı farklı bir r-kare değerini nasıl elde eder?
Travis Beale

1
Doğrusal bir regresyon uyumu ve bir polinom modelinin uyumu excel'e mi veriyorsunuz? İki veri dizisinden rsq'yi hesaplayacak ve ona doğrusal bir modelden uygunlukları verdiğinizi varsayacak. Excel ne veriyorsun? Excel'deki 'en uygun trend çizgisi' komutu nedir?
Baltimark

Excel'in grafik işlevlerinin bir parçasıdır. Bazı verilerin grafiğini çizebilir, üzerine sağ tıklayabilir ve ardından birkaç farklı trend çizgisi türü arasından seçim yapabilirsiniz. Doğrunun denklemini ve her tür için r-kare değerini görme seçeneği vardır. R kare değeri de her tür için farklıdır.
Travis Beale

@Travis Beale - denediğiniz her farklı ortalama fonksiyon için farklı bir r-kare elde edeceksiniz (iki model iç içe olmadıkça ve daha büyük modeldeki ekstra katsayıların tümü 0 olarak çalışmadıkça). Tabii ki Excel farklı bir r kare değerleri verir. @Baltimark - bu doğrusal regresyondur, bu yüzden r-kare.
leif


5

Python ve Numpy ile ağırlıklı r-kareyi hesaplamak için bir fonksiyon (kodun çoğu sklearn'dan gelir):

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

Misal:

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

çıktılar:

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

Bu, formüle ( ayna ) karşılık gelir :

görüntü açıklamasını buraya girin

f_i uyumdan tahmin edilen değerdir, y_ {av} gözlemlenen verilerin ortalamasıdır y_i gözlemlenen veri değeridir. w_i, her veri noktasına uygulanan ağırlıktır, genellikle w_i = 1. SSE, hatadan kaynaklanan karelerin toplamıdır ve SST, karelerin toplamıdır.


İlgileniyorsanız, R'deki kod: https://gist.github.com/dhimmel/588d64a73fa4fef02c8f ( ayna )


2

Y ve y_hat'in pandalar dizisi olduğunu varsayarak gerçek ve tahmin edilen değerlerden R ^ 2'yi hesaplamak için çok basit bir python işlevi:

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

Scipy.stats.linregress kaynağından. Ortalama kareler toplamı yöntemini kullanırlar.

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

Bu kodu doğrudan çalıştırabilirsiniz, bu size polinomu bulacaktır ve daha fazla açıklamaya ihtiyacınız olursa aşağıya bir yorum yazabileceğiniz R-değerini bulacaktı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)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.