我有两个阶段的数据:
import numpy as np
data_pre = np.array([[1., 2., 203.],
[0.5, np.nan, 208.]])
data_post = np.array([[2., 2., 203.],
[0.5, 2., 208.]])
我还有两个预先存在的拟合估计器:
from sklearn.preprocessing import Imputer
from sklearn.ensemble import GradientBoostingRegressor
imp = Imputer(missing_values=np.nan, strategy='mean', axis=1).fit(data_pre)
gbm = GradientBoostingRegressor().fit(data_post[:,:2], data_post[:,2])
我需要传递一个合适的管道并data_pre
到另一个函数。
def the_function_i_need(estimators):
"""
"""
return fitted pipeline
fitted_pipeline = the_function_i_need([imp, gbm])
sweet_output = static_function(fitted_pipeline, data_pre)
有没有办法在不重新拟合模型的情况下将这两个现有和拟合的模型对象组合到拟合的管道中,还是我不走运?
我试着研究这个。我找不到任何直接的方法。
我觉得唯一的方法是编写一个自定义转换器,它作为现有Imputer和GradientBoostingRegressor的包装器。您可以使用已经安装的回归器和/或插补器初始化包装器。然后,您可以通过不执行任何操作来覆盖对fit
的调用。在所有后续transform
调用中,可以调用基础拟合模型的transform
。这是一种肮脏的方式,除非这对您的应用程序非常重要,否则不应这样做。可以在此处找到有关为Scikit-Learn管道编写自定义类的良好教程。scikit-learn文档中自定义管道对象的另一个工作示例可以在这里找到。
...几年后。 使用make_pipeline()
将 scikit-learn 估计器连接为:
new_model = make_pipeline(fitted_preprocessor,
fitted_model)
詳細說明Abhinav Arora的答案:
在管道上调用predict
调用管道的最后一步predict
,对所有中间步骤transform
调用。因此,如果我们包括一个预处理模型(估计器而不是转换器)作为管道中的中间步骤,我们需要将中间估计器的predict()
方法别名为transform()
。
举个例子:
# Set up some data
import numpy as np
X = np.random.random((10,2)) # <- input into first model
y = np.random.random(10) # <- This data represents output from first model,
# and input into next model
z = np.random.random(10) # <- output from second model, final predictor
现在,让我们设置两个模型。第一个对X
进行操作以预测y
,第二个对y
进行操作以预测z
。
from sklearn.linear_model import LinearRegression
mod1 = LinearRegression().fit(X,y.reshape(-1,1))
mod2 = LinearRegression().fit(y.reshape(-1,1),z.reshape(-1,1))
[这里的reshape
方法只是转换列数组中的向量。
现在,每个模型都可以分别用于mod1.predict(X)
和mod2.predict(y.reshape(-1,1))
进行预测。但是,如果我们在管道中组合它们:
from sklearn.pipeline import Pipeline
p=Pipeline([('mod1', mod1),
('mod2', mod2)])
p.predict(X)
失败并显示错误:
AttributeError: 'LinearRegression' object has no attribute 'transform'
它指的是mod1
的方法(属性)。所以我们需要按照阿比纳夫·阿罗拉的回答,围绕mod1
写一个包装器。
from sklearn.base import BaseEstimator
class Wrapper(BaseEstimator):
def __init__(self,
intermediate_model): # Pass through the estimator here
self.intermediate_model = intermediate_model
def fit(self, X, y=None): # Assume model has already been fit
return self # so do nothing here
def transform(self, X):
return self.intermediate_model.predict(X) # alias predict as transform
wrapped_mod1 = Wrapper(mod1)
然后wrapped_mod1.transform(X)
生成与mod1.predict(X)
相同的输出。
现在
p2=Pipeline([('mod1', wrapped_mod1),
('mod2', mod2)])
p2.predict(X)
按预期工作。
注意:此方法在管道上调用predict
时有效,但在cross_validate
和GridSearchCV
等中失败。在这些函数中,包装的估计器被克隆并重置为未拟合状态。让管道在cross_validate
等中工作的解决方法是通过序列化(酸洗)并重新加载来"冻结"包装的估计器。
您可以使用以下代码在scikit-learn中创建管道,将其与训练数据拟合,向管道添加拟合的估计器,并评估其在测试数据上的性能:
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.linear_model import RidgeClassifier
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
# Load the Iris dataset
data = load_iris()
X, y = data.data, data.target
# Split the data into training and test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# Create the initial pipeline
pipeline = Pipeline([
('scaler', StandardScaler()),
('model', RidgeClassifier())
])
# Fit the pipeline on the training data
pipeline.fit(X_train, y_train)
# Create a new LogisticRegression estimator
estimator = LogisticRegression(solver='liblinear')
# Fit the estimator on the training data
estimator.fit(X_train, y_train)
# Add the fitted estimator to the pipeline
pipeline.set_params(model=estimator)
# Evaluate the pipeline with the added estimator on the test data
y_pred = pipeline.predict_proba(X_test)
accuracy = pipeline.score(X_test, y_test)
print("Accuracy:", accuracy)
Accuracy: 0.9666666666666667
管道拟合在训练数据上,然后创建一个新的 LogisticRegression 估计器实例并拟合在同一训练数据上。然后使用 pipeline.set_params() 将拟合的估计器添加到管道中。