web-dev-qa-db-ja.com

statsmodel推定をscikit-learnクロス検証で使用することは可能ですか?

私はこの質問をCrossValidatedフォーラムに投稿しましたが、後で、代わりにstackoverlfowで適切なオーディエンスが見つかる可能性があることに気付きました。

python statsmodelから取得したfitオブジェクト(結果)を使用して、scikit-learncross_validationメソッドのcross_val_scoreにフィードする方法を探していますか?添付リンクはそれが可能かもしれないことを示唆していますが、私は成功していません。

次のエラーが発生します

estimatorは、「fit」メソッドを実装する推定器である必要があります。statsmodels.discrete.discrete_model.BinaryResultsWrapperオブジェクト(0x7fa6e801c590)が渡されました

このリンクを参照

17
CARTman

実際、インターフェースが異なるため、statsmodelsオブジェクトでcross_val_scoreを直接使用することはできません。statsmodelsで

  • トレーニングデータはコンストラクターに直接渡されます
  • 別のオブジェクトには、モデル推定の結果が含まれています

ただし、statsmodelsオブジェクトをsklearn推定量のように見せるための単純なラッパーを作成できます。

import statsmodels.api as sm
from sklearn.base import BaseEstimator, RegressorMixin

class SMWrapper(BaseEstimator, RegressorMixin):
    """ A universal sklearn-style wrapper for statsmodels regressors """
    def __init__(self, model_class, fit_intercept=True):
        self.model_class = model_class
        self.fit_intercept = fit_intercept
    def fit(self, X, y):
        if self.fit_intercept:
            X = sm.add_constant(X)
        self.model_ = self.model_class(y, X)
        self.results_ = self.model_.fit()
    def predict(self, X):
        if self.fit_intercept:
            X = sm.add_constant(X)
        return self.results_.predict(X)

このクラスには、正しいfitメソッドとpredictメソッドが含まれており、sklearnとともに使用できます。相互検証されているか、パイプラインに含まれています。ここみたいに:

from sklearn.datasets import make_regression
from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LinearRegression

X, y = make_regression(random_state=1, n_samples=300, noise=100)

print(cross_val_score(SMWrapper(sm.OLS), X, y, scoring='r2'))
print(cross_val_score(LinearRegression(), X, y, scoring='r2'))

2つのモデルは両方ともOLSモデルであり、同じ方法で相互検証されているため、2つのモデルの出力は同じであることがわかります。

[0.28592315 0.37367557 0.47972639]
[0.28592315 0.37367557 0.47972639]
24
David Dale

Davidの提案 (エラーが発生し、関数_get_parameters_がないことについて不平を言っています)と scikit learnドキュメント に続いて、線形の次のラッパーを作成しました回帰。 _sklearn.linear_model.LinearRegression_と同じインターフェースを備えていますが、さらに_statsmodels.OLS_のように、p値、R2、およびその他の統計に関する情報を提供する関数summary()も備えています。

_import statsmodels.api as sm
from sklearn.base import BaseEstimator, RegressorMixin
import pandas as pd
import numpy as np

from sklearn.utils.multiclass import check_classification_targets
from sklearn.utils.validation import check_X_y, check_is_fitted, check_array
from sklearn.utils.multiclass import unique_labels
from sklearn.utils.estimator_checks import check_estimator



class MyLinearRegression(BaseEstimator, RegressorMixin):
    def __init__(self, fit_intercept=True):

        self.fit_intercept = fit_intercept


    """
    Parameters
    ------------
    column_names: list
            It is an optional value, such that this class knows 
            what is the name of the feature to associate to 
            each column of X. This is useful if you use the method
            summary(), so that it can show the feature name for each
            coefficient
    """ 
    def fit(self, X, y, column_names=() ):

        if self.fit_intercept:
            X = sm.add_constant(X)

        # Check that X and y have correct shape
        X, y = check_X_y(X, y)


        self.X_ = X
        self.y_ = y

        if len(column_names) != 0:
            cols = column_names.copy()
            cols = list(cols)
            X = pd.DataFrame(X)
            cols = column_names.copy()
            cols.insert(0,'intercept')
            print('X ', X)
            X.columns = cols

        self.model_ = sm.OLS(y, X)
        self.results_ = self.model_.fit()
        return self



    def predict(self, X):
        # Check is fit had been called
        check_is_fitted(self, 'model_')

        # Input validation
        X = check_array(X)

        if self.fit_intercept:
            X = sm.add_constant(X)
        return self.results_.predict(X)


    def get_params(self, deep = False):
        return {'fit_intercept':self.fit_intercept}


    def summary(self):
        print(self.results_.summary() )
_

使用例:

_cols = ['feature1','feature2']
X_train = df_train[cols].values
X_test = df_test[cols].values
y_train = df_train['label']
y_test = df_test['label']
model = MyLinearRegression()
model.fit(X_train, y_train)
model.summary()
model.predict(X_test)
_

列の名前を表示したい場合は、

_model.fit(X_train, y_train, column_names=cols)
_

Cross_validationで使用するには:

_from sklearn.model_selection import cross_val_score
scores = cross_val_score(MyLinearRegression(), X_train, y_train, cv=10, scoring='neg_mean_squared_error')
scores
_
1
Andrea Araldo

参考までに、statsmodels式APIを使用するか、fit_regularizedメソッドを使用する場合、この方法で@DavidDaleのラッパークラスを変更できます。

import pandas as pd
from sklearn.base import BaseEstimator, RegressorMixin
from statsmodels.formula.api import glm as glm_sm

# This is an example wrapper for statsmodels GLM
class SMWrapper(BaseEstimator, RegressorMixin):
    def __init__(self, family, formula, alpha, L1_wt):
        self.family = family
        self.formula = formula
        self.alpha = alpha
        self.L1_wt = L1_wt
        self.model = None
        self.result = None
    def fit(self, X, y):
        data = pd.concat([pd.DataFrame(X), pd.Series(y)], axis=1)
        data.columns = X.columns.tolist() + ['y']
        self.model = glm_sm(self.formula, data, family=self.family)
        self.result = self.model.fit_regularized(alpha=self.alpha, L1_wt=self.L1_wt, refit=True)
        return self.result
    def predict(self, X):
        return self.result.predict(X)
0
cylim

これは技術的にはscikit-learnではないと思いますが、statsmodelをラップし、scikit-learnのようなインターフェイスを提供するパッケージ pmdarima があります。

0
sh0rtcircuit