web-dev-qa-db-ja.com

PythonとNumpyを使用してr 2乗を計算するにはどうすればよいですか?

PythonとNumpyを使用して、任意の次数の最適な多項式を計算しています。 x値、y値、および近似する多項式の次数(線形、2次など)のリストを渡します。

これは非常に効果的ですが、r(相関係数)とr-2乗(決定係数)も計算したいと思います。結果をExcelの最適な近似曲線機能と、それが計算するr 2乗値と比較しています。これを使用して、線形ベストフィット(次数が1)のr二乗を正しく計算していることがわかります。ただし、私の関数は次数が1より大きい多項式では機能しません。

Excelはこれを行うことができます。 Numpyを使用して高次多項式のr 2乗を計算するにはどうすればよいですか?

私の機能は次のとおりです。

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
79
Travis Beale

numpy.polyfit ドキュメントから、線形回帰に適合しています。具体的には、次数が 'd'のnumpy.polyfitは、平均関数の線形回帰に適合します。

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

そのため、その近似のR 2乗を計算するだけです。 線形回帰 のウィキペディアページに詳細が記載されています。いくつかの方法で計算できる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の平均に「y_bar」を使用し、各ポイントのフィット値に「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
54
leif

非常に遅い返信。ただし、誰かがこのための準備ができた機能を必要とする場合に備えて:

scipy.stats.linregress

つまり.

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

@Adam Marplesの答えのように。

107
Gökhan Sever

私はこれをうまく使っています。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
19
Adam Marples

私はもともと、numpy.corrcoefを推奨する目的で以下のベンチマークを投稿しました。元の質問が既にcorrcoefを使用しており、実際には高次の多項式近似について尋ねていたことに気づかずに。 statsmodelsを使用して、多項式のr 2乗問題に実際のソリューションを追加しました。元のベンチマークは残しました。


statsmodelsには、多項式近似のr^2を直接計算する機能があります。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)ポイントに対して多数のメソッドを比較した結果です。

  • Pure Python(直接r計算)
    • 1000ループ、ベスト3:ループあたり1.59ミリ秒
  • ナンピーポリフィット(n次多項式フィットに適用)
    • 1000ループ、最高3:ループあたり326μs
  • Numpy Manual(直接r計算)
    • 10000ループ、最高3:ループあたり62.1 µs
  • Numpy corrcoef(直接r計算)
    • 10000ループ、最高3:ループあたり56.6 µs
  • Scipy(出力としてrを使用した線形回帰)
    • 1000ループ、最高3:ループあたり676 µs
  • Statsmodels(n次の多項式と他の多くの近似を行うことができます)
    • 1000ループ、最高3:ループあたり422 µs

Corrcoefメソッドは、numpyメソッドを使用してr ^ 2を「手動で」計算することに勝ります。 polyfitメソッドより5倍以上高速で、scipy.linregressより12倍高速です。 numpyの機能を強化するために、純粋なpythonよりも28倍高速です。私はnumbaやpypyのようなものに精通していないので、他の誰かがそれらのギャップを埋める必要がありますが、これはcorrcoefrを計算するための最良のツールであることを私に確信させると思います単純な線形回帰の場合。

これが私のベンチマークコードです。 Jupyter Notebookからコピーアンドペーストしました(IPython Notebookと呼ぶのは難しいことではありません...)。そのため、途中で何かが壊れた場合は謝罪します。 %timeitマジックコマンドには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)
15
flutefreak7

以下は、weightedr-squaredをPythonとNumpy(ほとんどのコードは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 __== "__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

これは )に対応します:

enter image description here

f_iは近似からの予測値、y_ {av}は観測データの平均ですy_iは観測データ値です。 w_iは各データポイントに適用される重み付けで、通常はw_i = 1です。 SSEはエラーによる平方和で、SSTは平方和の合計です。


興味がある場合、Rのコード: https://Gist.github.com/dhimmel/588d64a73fa4fef02c8fmirror

5

r-squareds に関するウィキペディアの記事は、単なる線形回帰ではなく、一般的なモデルフィッティングに使用できることを示唆しています。

5
Glenton

R-2乗は、線形回帰のみに適用される統計です。

基本的に、線形回帰によって説明できるデータの変動量を測定します。

したがって、「合計平方和」を計算します。これは、各結果変数の平均からの合計平方偏差です。 。 。

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

ここで、y_barはyの平均です。

次に、「回帰二乗和」を計算します。これは、FITTED値が平均値とどの程度異なるかです

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

そして、これら2つの比率を見つけます。

これで、多項式近似に必要なことは、そのモデルからのy_hatをプラグインすることだけですが、そのr-2乗と呼ぶのは正確ではありません。

ここ は、私が見つけたリンクです。

4
Baltimark