我正在尝试使用GridSearchCV创建一个管道,以过滤数据(使用iForest)并执行标准化(StandardScaler)后的回归(MLPRegressor)。
我创建了一个FunctionTransformer来将我的iForest过滤器包含在管道中。我还为iForest过滤器定义了一个参数网格(使用kw_args方法)。
一切看起来都正常,但在执行fit操作时,什么都没有发生…没有错误消息,什么都没有。
之后,当我想进行预测时,我收到了消息:“此RandomizedSearchCV实例尚未拟合”。
from sklearn.preprocessing import FunctionTransformer#使用iForest算法定义自动过滤函数def auto_filter(DF, conta=0.1): #在DF数据框上应用iForest iforest = IsolationForest(behaviour='new', n_estimators=300, max_samples='auto', contamination=conta) iforest = iforest.fit(DF) #仅考虑内点观察值来过滤输入的DF数据框 data_filtered = DF[iforest.predict(DF) == 1] #仅保留少数变量用于下一步(由MLPRegressor进行的回归) #此函数返回X_filtered和y X_filtered = data_filtered[['SessionTotalTime','AverageHR','MaxHR','MinHR','EETotal','EECH','EEFat','TRIMP','BeatByBeatRMSSD','BeatByBeatSD','HFAverage','LFAverage','LFHFRatio','Weight']] y = data_filtered['MaxVO2'] return (X_filtered, y)#定义管道('auto_filter' --> 'scaler' --> 'MLPRegressor') pipeline_steps = [('auto_filter', FunctionTransformer(auto_filter)), ('scaler', StandardScaler()), ('MLPR', MLPRegressor(solver='lbfgs', activation='relu', early_stopping=True, n_iter_no_change=20, validation_fraction=0.2, max_iter=10000))]#定义Gridsearch,包含管道第一阶段('auto_filter')的不同'conta'值parameters = {'auto_filter__kw_args': [{'conta': 0.1}, {'conta': 0.2}, {'conta': 0.3}], 'MLPR__hidden_layer_sizes':[(sp_randint.rvs(1, nb_features, 1),), (sp_randint.rvs(1, nb_features, 1), sp_randint.rvs(1, nb_features, 1))], 'MLPR__alpha':sp_rand.rvs(0, 1, 1)} pipeline = Pipeline(pipeline_steps)estimator = RandomizedSearchCV(pipeline, parameters, cv=5, n_iter=10)estimator.fit(X_train, y_train)
回答:
FunctionTransformer
的func
参数应为可调用对象,其接受与transform
方法相同的参数(形状为(n_samples, n_features)
的类似数组的X
和func
的kwargs
),并返回相同形状的变换后的X
。您的auto_filter
函数不符合这些要求。
此外,scikit-learn中的异常/离群点检测技术不能作为scikit-learn管道的中间步骤使用,因为管道由一个或多个transformers
和一个可选的最终估计器组成。IsolationForest
或例如OneClassSVM
不是变换器:它们实现了fit
和predict
。因此,一个可能的解决方案是单独剔除可能的离群点,并构建由变换器和回归器组成的管道:
>>> import warnings>>> from sklearn.exceptions import ConvergenceWarning>>> warnings.filterwarnings(category=ConvergenceWarning, action='ignore')>>> import numpy as np>>> from scipy import stats>>> from sklearn.datasets import make_regression>>> from sklearn.ensemble import IsolationForest>>> from sklearn.model_selection import RandomizedSearchCV>>> from sklearn.neural_network import MLPRegressor>>> from sklearn.pipeline import Pipeline>>> from sklearn.preprocessing import StandardScaler>>> X, y = make_regression(n_samples=50, n_features=2, n_informative=2)>>> detect = IsolationForest(contamination=0.1, behaviour='new')>>> inliers_mask = detect.fit_predict(X) == 1>>> pipe = Pipeline([('scale', StandardScaler()),... ('estimate', MLPRegressor(max_iter=500, tol=1e-5))])>>> param_distributions = dict(estimate__alpha=stats.uniform(0, 0.1))>>> search = RandomizedSearchCV(pipe, param_distributions,... n_iter=2, cv=3, iid=True)>>> search = search.fit(X[inliers_mask], y[inliers_mask])
问题在于您将无法优化IsolationForest
的超参数。一种处理方法是为森林定义超参数空间,使用ParameterSampler
或ParameterGrid
抽样超参数,预测内点并拟合随机搜索:
>>> from sklearn.model_selection import ParameterGrid>>> forest_param_dict = dict(contamination=[0.1, 0.15, 0.2])>>> forest_param_grid = ParameterGrid(forest_param_dict)>>> for sample in forest_param_grid:... detect = detect.set_params(contamination=sample['contamination'])... inliers_mask = detect.fit_predict(X) == 1... search.fit(X[inliers_mask], y[inliers_mask])