Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/278.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 通过scikit学习交叉验证使用statsmodel估计,是否可能?_Python_Scikit Learn_Cross Validation_Statsmodels - Fatal编程技术网

Python 通过scikit学习交叉验证使用statsmodel估计,是否可能?

Python 通过scikit学习交叉验证使用statsmodel估计,是否可能?,python,scikit-learn,cross-validation,statsmodels,Python,Scikit Learn,Cross Validation,Statsmodels,我将这个问题发布到交叉验证论坛,后来意识到这可能会在stackoverlfow中找到合适的受众 我正在寻找一种方法,可以使用python statsmodel中包含的fit对象(结果)来输入scikit学习交叉验证方法的cross\u val\u score? 所附的链接表明这是可能的,但我没有成功 我得到以下错误 估计器应该是一个实现“拟合”方法的估计器 位于的statsmodels.discrete.discrete_model.BinaryResultsWrapper对象 0x7fa6e8

我将这个问题发布到交叉验证论坛,后来意识到这可能会在stackoverlfow中找到合适的受众

我正在寻找一种方法,可以使用python statsmodel中包含的
fit
对象(结果)来输入scikit学习交叉验证方法的
cross\u val\u score
? 所附的链接表明这是可能的,但我没有成功

我得到以下错误

估计器应该是一个实现“拟合”方法的估计器 位于的statsmodels.discrete.discrete_model.BinaryResultsWrapper对象 0x7fa6e801c590已通过


事实上,您不能直接在
statsmodels
对象上使用
交叉评分
,因为界面不同:在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'))
您可以看到两个模型的输出是相同的,因为它们都是OLS模型,以相同的方式进行交叉验证

[0.28592315 0.37367557 0.47972639]
[0.28592315 0.37367557 0.47972639]

出于参考目的,如果您使用
statsmodels
formula API和/或使用
fit_regulated
方法,则可以这样修改@David Dale的包装类

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)

虽然我认为这在技术上不是scikit learn,但是有一个包包装了statsmodel并提供了一个类似scikit learn的界面。

继(这给了我一个错误,抱怨缺少函数
get\u参数)和之后,我为线性回归创建了以下包装。
它具有与
sklearn.linear\u model.LinearRegression
相同的界面,但还具有函数
summary()
,该函数提供有关p值、R2和其他统计信息,如
statsmodels.OLS

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)
要在交叉验证中使用它,请执行以下操作:

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

你好,安德烈。请考虑在您的答案中添加更多的信息,而不是链接到外部源。在最后一个注释“在交叉验证中使用它”,为什么您使用XySrand和YyTrm,而不是仅仅X和Y,因为我考虑以下协议:(i)在训练和测试集中划分样本(ii)选择最佳模型,即,仅使用训练集即可获得最高交叉验证分数,以避免任何数据泄漏(iii)在测试集中包含的“未看到”数据上检查此类模型的性能。如果使用整个集合进行交叉验证,则将基于相同的数据选择模型,然后根据这些数据判断模型。从技术上讲,这将是一次数据泄漏。事实上,它不会给你一个关于你的模型在完全看不见的数据下的行为的指示。知道原因是什么吗?