Temukan p-value (signifikansi) di scikit-learn LinearRegression


154

Bagaimana saya bisa menemukan nilai-p (signifikansi) dari masing-masing koefisien?

lm = sklearn.linear_model.LinearRegression()
lm.fit(x,y)

2
Bukan jawaban Anda, tetapi mungkin jawaban untuk orang lain: scipy memberikan pvalues ​​in linregress: docs.scipy.org/doc/scipy-0.14.0/reference/generated/…
DaveRGP

itu hanya bekerja untuk satu dimensi vs satu dimensi.
Richard Liang

Jawaban:


162

Ini agak berlebihan tapi mari kita coba. Pertama mari kita gunakan statsmodel untuk mencari tahu apa nilai-p seharusnya

import pandas as pd
import numpy as np
from sklearn import datasets, linear_model
from sklearn.linear_model import LinearRegression
import statsmodels.api as sm
from scipy import stats

diabetes = datasets.load_diabetes()
X = diabetes.data
y = diabetes.target

X2 = sm.add_constant(X)
est = sm.OLS(y, X2)
est2 = est.fit()
print(est2.summary())

dan kita dapatkan

                         OLS Regression Results                            
==============================================================================
Dep. Variable:                      y   R-squared:                       0.518
Model:                            OLS   Adj. R-squared:                  0.507
Method:                 Least Squares   F-statistic:                     46.27
Date:                Wed, 08 Mar 2017   Prob (F-statistic):           3.83e-62
Time:                        10:08:24   Log-Likelihood:                -2386.0
No. Observations:                 442   AIC:                             4794.
Df Residuals:                     431   BIC:                             4839.
Df Model:                          10                                         
Covariance Type:            nonrobust                                         
==============================================================================
                 coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------
const        152.1335      2.576     59.061      0.000     147.071     157.196
x1           -10.0122     59.749     -0.168      0.867    -127.448     107.424
x2          -239.8191     61.222     -3.917      0.000    -360.151    -119.488
x3           519.8398     66.534      7.813      0.000     389.069     650.610
x4           324.3904     65.422      4.958      0.000     195.805     452.976
x5          -792.1842    416.684     -1.901      0.058   -1611.169      26.801
x6           476.7458    339.035      1.406      0.160    -189.621    1143.113
x7           101.0446    212.533      0.475      0.635    -316.685     518.774
x8           177.0642    161.476      1.097      0.273    -140.313     494.442
x9           751.2793    171.902      4.370      0.000     413.409    1089.150
x10           67.6254     65.984      1.025      0.306     -62.065     197.316
==============================================================================
Omnibus:                        1.506   Durbin-Watson:                   2.029
Prob(Omnibus):                  0.471   Jarque-Bera (JB):                1.404
Skew:                           0.017   Prob(JB):                        0.496
Kurtosis:                       2.726   Cond. No.                         227.
==============================================================================

Ok, mari kita mereproduksi ini. Ini agak berlebihan karena kita hampir mereproduksi analisis regresi linier menggunakan Matriks Aljabar. Tapi apa-apaan ini.

lm = LinearRegression()
lm.fit(X,y)
params = np.append(lm.intercept_,lm.coef_)
predictions = lm.predict(X)

newX = pd.DataFrame({"Constant":np.ones(len(X))}).join(pd.DataFrame(X))
MSE = (sum((y-predictions)**2))/(len(newX)-len(newX.columns))

# Note if you don't want to use a DataFrame replace the two lines above with
# newX = np.append(np.ones((len(X),1)), X, axis=1)
# MSE = (sum((y-predictions)**2))/(len(newX)-len(newX[0]))

var_b = MSE*(np.linalg.inv(np.dot(newX.T,newX)).diagonal())
sd_b = np.sqrt(var_b)
ts_b = params/ sd_b

p_values =[2*(1-stats.t.cdf(np.abs(i),(len(newX)-len(newX[0])))) for i in ts_b]

sd_b = np.round(sd_b,3)
ts_b = np.round(ts_b,3)
p_values = np.round(p_values,3)
params = np.round(params,4)

myDF3 = pd.DataFrame()
myDF3["Coefficients"],myDF3["Standard Errors"],myDF3["t values"],myDF3["Probabilities"] = [params,sd_b,ts_b,p_values]
print(myDF3)

Dan ini memberi kita.

    Coefficients  Standard Errors  t values  Probabilities
0       152.1335            2.576    59.061         0.000
1       -10.0122           59.749    -0.168         0.867
2      -239.8191           61.222    -3.917         0.000
3       519.8398           66.534     7.813         0.000
4       324.3904           65.422     4.958         0.000
5      -792.1842          416.684    -1.901         0.058
6       476.7458          339.035     1.406         0.160
7       101.0446          212.533     0.475         0.635
8       177.0642          161.476     1.097         0.273
9       751.2793          171.902     4.370         0.000
10       67.6254           65.984     1.025         0.306

Jadi kita dapat mereproduksi nilai dari statsmodel.


2
apa artinya var_b saya semua Nans? Apakah ada alasan mendasar mengapa bagian aljabar linier gagal?
famargar

Sangat sulit ditebak mengapa itu bisa terjadi. Saya akan melihat struktur data Anda dan membandingkannya dengan contoh. Itu mungkin memberikan petunjuk.
JARH

1
Sepertinya codenp.linalg.inv kadang-kadang dapat mengembalikan hasil bahkan ketika matriks tidak dapat dibalik. Mungkin itu masalahnya.
JARH

7
@amaramar Saya juga punya masalah semua nans. Bagi saya itu karena Xdata sampel saya jadi indeksnya mati. Ini menyebabkan kesalahan saat memanggil pd.DataFrame.join(). Saya membuat perubahan satu baris ini dan sepertinya berfungsi sekarang:newX = pd.DataFrame({"Constant":np.ones(len(X))}).join(pd.DataFrame(X.reset_index(drop=True)))
pault

1
@ mLstudent33 Kolom "probabilitas".
skeller88

52

scear-learn's LinearRegression tidak menghitung informasi ini tetapi Anda dapat dengan mudah memperluas kelas untuk melakukannya:

from sklearn import linear_model
from scipy import stats
import numpy as np


class LinearRegression(linear_model.LinearRegression):
    """
    LinearRegression class after sklearn's, but calculate t-statistics
    and p-values for model coefficients (betas).
    Additional attributes available after .fit()
    are `t` and `p` which are of the shape (y.shape[1], X.shape[1])
    which is (n_features, n_coefs)
    This class sets the intercept to 0 by default, since usually we include it
    in X.
    """

    def __init__(self, *args, **kwargs):
        if not "fit_intercept" in kwargs:
            kwargs['fit_intercept'] = False
        super(LinearRegression, self)\
                .__init__(*args, **kwargs)

    def fit(self, X, y, n_jobs=1):
        self = super(LinearRegression, self).fit(X, y, n_jobs)

        sse = np.sum((self.predict(X) - y) ** 2, axis=0) / float(X.shape[0] - X.shape[1])
        se = np.array([
            np.sqrt(np.diagonal(sse[i] * np.linalg.inv(np.dot(X.T, X))))
                                                    for i in range(sse.shape[0])
                    ])

        self.t = self.coef_ / se
        self.p = 2 * (1 - stats.t.cdf(np.abs(self.t), y.shape[0] - X.shape[1]))
        return self

Dicuri dari sini .

Anda harus melihat statsmodels untuk jenis analisis statistik dengan Python.


Baik. Ini tidak bekerja karena sse adalah skalar jadi sse.shape tidak benar-benar berarti apa-apa.
ashu

15

EDIT: Mungkin bukan cara yang tepat untuk melakukannya, lihat komentar

Anda dapat menggunakan sklearn.feature_selection.f_regress.

klik di sini untuk halaman scikit-learn


1
Jadi itu adalah tes-F? Saya pikir nilai-p untuk regresi linier biasanya untuk setiap individu regressor, dan itu adalah tes vs nol dari koefisien menjadi 0? Penjelasan lebih lanjut tentang fungsi akan diperlukan untuk jawaban yang baik.
kata

Halaman dokumentasi @wordsforthewise mengatakan bahwa nilai yang dikembalikan adalah array dari p_values. Jadi itu memang nilai untuk setiap individu regressor.
ashu

1
Jangan gunakan metode ini karena itu tidak benar! Itu melakukan regresi univariat, tetapi Anda mungkin ingin regresi multivariat tunggal
user357269

1
Tidak, jangan gunakan f_regress. Nilai p aktual dari masing-masing koefisien harus berasal dari uji t untuk setiap koefisien setelah pemasangan data. f_regress in sklearn berasal dari regresi univariat. Itu tidak membangun mode, hanya menghitung skor f untuk setiap variabel. Sama seperti fungsi chi2 di sklearn Ini benar: import statsmodels.api as sm mod = sm.OLS (Y, X)
Richard Liang

@ RichardLiang, gunakan sm.OLS () adalah cara yang benar untuk menghitung nilai-p (multivarian) untuk algoritma apa pun? (seperti pohon keputusan, svm, k-means, regresi logistik, dll)? Saya ingin metode generik untuk mendapatkan nilai-p. Terima kasih
Gilian

11

Kode dalam jawaban elyase https://stackoverflow.com/a/27928411/4240413 tidak benar-benar berfungsi. Perhatikan bahwa sse adalah skalar, dan kemudian mencoba untuk mengulanginya. Kode berikut adalah versi yang dimodifikasi. Tidak bersih luar biasa, tapi saya pikir itu berfungsi lebih atau kurang.

class LinearRegression(linear_model.LinearRegression):

    def __init__(self,*args,**kwargs):
        # *args is the list of arguments that might go into the LinearRegression object
        # that we don't know about and don't want to have to deal with. Similarly, **kwargs
        # is a dictionary of key words and values that might also need to go into the orginal
        # LinearRegression object. We put *args and **kwargs so that we don't have to look
        # these up and write them down explicitly here. Nice and easy.

        if not "fit_intercept" in kwargs:
            kwargs['fit_intercept'] = False

        super(LinearRegression,self).__init__(*args,**kwargs)

    # Adding in t-statistics for the coefficients.
    def fit(self,x,y):
        # This takes in numpy arrays (not matrices). Also assumes you are leaving out the column
        # of constants.

        # Not totally sure what 'super' does here and why you redefine self...
        self = super(LinearRegression, self).fit(x,y)
        n, k = x.shape
        yHat = np.matrix(self.predict(x)).T

        # Change X and Y into numpy matricies. x also has a column of ones added to it.
        x = np.hstack((np.ones((n,1)),np.matrix(x)))
        y = np.matrix(y).T

        # Degrees of freedom.
        df = float(n-k-1)

        # Sample variance.     
        sse = np.sum(np.square(yHat - y),axis=0)
        self.sampleVariance = sse/df

        # Sample variance for x.
        self.sampleVarianceX = x.T*x

        # Covariance Matrix = [(s^2)(X'X)^-1]^0.5. (sqrtm = matrix square root.  ugly)
        self.covarianceMatrix = sc.linalg.sqrtm(self.sampleVariance[0,0]*self.sampleVarianceX.I)

        # Standard erros for the difference coefficients: the diagonal elements of the covariance matrix.
        self.se = self.covarianceMatrix.diagonal()[1:]

        # T statistic for each beta.
        self.betasTStat = np.zeros(len(self.se))
        for i in xrange(len(self.se)):
            self.betasTStat[i] = self.coef_[0,i]/self.se[i]

        # P-value for each beta. This is a two sided t-test, since the betas can be 
        # positive or negative.
        self.betasPValue = 1 - t.cdf(abs(self.betasTStat),df)

8

Cara mudah untuk menarik nilai-p adalah dengan menggunakan regresi statsmodels:

import statsmodels.api as sm
mod = sm.OLS(Y,X)
fii = mod.fit()
p_values = fii.summary2().tables[1]['P>|t|']

Anda mendapatkan serangkaian nilai-p yang dapat Anda manipulasi (misalnya memilih urutan yang ingin Anda pertahankan dengan mengevaluasi setiap nilai-p):

masukkan deskripsi gambar di sini


Gunakan sm.OLS () adalah cara yang benar untuk menghitung nilai-p (multivarian) untuk algoritma apa pun? (seperti pohon keputusan, svm, k-means, regresi logistik, dll)? Saya ingin metode generik untuk mendapatkan nilai-p. Terima kasih
Gilian

7

p_value adalah salah satu dari f statistik. jika Anda ingin mendapatkan nilainya, cukup gunakan beberapa baris kode ini:

import statsmodels.api as sm
from scipy import stats

diabetes = datasets.load_diabetes()
X = diabetes.data
y = diabetes.target

X2 = sm.add_constant(X)
est = sm.OLS(y, X2)
print(est.fit().f_pvalue)

3
Ini tidak menjawab pertanyaan karena Anda menggunakan perpustakaan yang berbeda dari yang disebutkan.
gented

@gented Apa skenario di mana satu metode perhitungan akan lebih baik daripada yang lain?
Don Quixote

6

Mungkin ada kesalahan dalam jawaban @JARH dalam kasus regresi multivariabel. (Saya tidak memiliki reputasi yang cukup untuk berkomentar.)

Di baris berikut:

p_values =[2*(1-stats.t.cdf(np.abs(i),(len(newX)-1))) for i in ts_b],

t-nilai mengikuti distribusi chi-squared derajat len(newX)-1bukannya mengikuti distribusi chi-squared derajat len(newX)-len(newX.columns)-1.

Jadi ini seharusnya:

p_values =[2*(1-stats.t.cdf(np.abs(i),(len(newX)-len(newX.columns)-1))) for i in ts_b]

(Lihat nilai-t untuk regresi OLS untuk lebih jelasnya)


5

Anda dapat menggunakan scipy untuk nilai-p. Kode ini dari dokumentasi yang lemah.

>>> from scipy import stats
>>> import numpy as np
>>> x = np.random.random(10)
>>> y = np.random.random(10)
>>> slope, intercept, r_value, p_value, std_err = stats.linregress(x,y)

1
Saya tidak berpikir ini berlaku untuk beberapa vektor yang digunakan selama fit
O.rka

1

Untuk one-liner, Anda dapat menggunakan fungsi pingouin.linear_regress ( penafian: Saya pencipta Pingouin ), yang berfungsi dengan regresi uni / multi-variasi menggunakan array NumPy atau Pandas DataFrame, mis::

import pingouin as pg
# Using a Pandas DataFrame `df`:
lm = pg.linear_regression(df[['x', 'z']], df['y'])
# Using a NumPy array:
lm = pg.linear_regression(X, y)

Outputnya adalah dataframe dengan koefisien beta, kesalahan standar, nilai-T, nilai-p dan interval kepercayaan untuk setiap prediktor, serta R ^ 2 dan penyesuaian R ^ 2 yang sesuai.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.