我正在尝试根据本教程的指导为Python sklearn管道创建自定义转换器:http://danielhnyk.cz/creating-your-own-estimator-scikit-learn/
现在我的自定义类/变换器如下所示:
class SelectBestPercFeats(BaseEstimator, TransformerMixin):
def __init__(self, model=RandomForestRegressor(), percent=0.8,
random_state=52):
self.model = model
self.percent = percent
self.random_state = random_state
def fit(self, X, y, **fit_params):
"""
Find features with best predictive power for the model, and
have cumulative importance value less than self.percent
"""
# Check parameters
if not isinstance(self.percent, float):
print("SelectBestPercFeats.percent is not a float, it should be...")
elif not isinstance(self.random_state, int):
print("SelectBestPercFeats.random_state is not a int, it should be...")
# If checks are good proceed with fitting...
else:
try:
self.model.fit(X, y)
except:
print("Error fitting model inside SelectBestPercFeats object")
return self
# Get feature importance
try:
feat_imp = list(self.model.feature_importances_)
feat_imp_cum = pd.Series(feat_imp, index=X.columns) \
.sort_values(ascending=False).cumsum()
# Get features whose cumulative importance is <= `percent`
n_feats = len(feat_imp_cum[feat_imp_cum <= self.percent].index) + 1
self.bestcolumns_ = list(feat_imp_cum.index)[:n_feats]
except:
print ("ERROR: SelectBestPercFeats can only be used with models with"\
" .feature_importances_ parameter")
return self
def transform(self, X, y=None, **fit_params):
"""
Filter out only the important features (based on percent threshold)
for the model supplied.
:param X: Dataframe with features to be down selected
"""
if self.bestcolumns_ is None:
print("Must call fit function on SelectBestPercFeats object before transforming")
else:
return X[self.bestcolumns_]
我正在将此类集成到这样的sklearn管道中:
# Define feature selection and model pipeline components
rf_simp = RandomForestRegressor(criterion='mse', n_jobs=-1,
n_estimators=600)
bestfeat = SelectBestPercFeats(rf_simp, feat_perc)
rf = RandomForestRegressor(n_jobs=-1,
criterion='mse',
n_estimators=200,
max_features=0.4,
)
# Build Pipeline
master_model = Pipeline([('feat_sel', bestfeat), ('rf', rf)])
# define GridSearchCV parameter space to search,
# only listing one parameter to simplify troubleshooting
param_grid = {
'feat_select__percent': [0.8],
}
# Fit pipeline model
grid = GridSearchCV(master_model, cv=3, n_jobs=-1,
param_grid=param_grid)
# Search grid using CV, and get the best estimator
grid.fit(X_train, y_train)
每当我运行最后一行代码(grid.fit(X_train, y_train)
)时,我都会得到以下“PicklingError”。任何人都可以在我的代码中看到导致此问题的原因吗?
或者,我的Python设置中有什么东西是错的......我可能会错过一个包或类似的东西吗?我刚刚检查过我可以import pickle
成功
Traceback(最近一次调用最后一次):文件“”,第5行,in 文件 “C:\用户\ jjaaae \应用程序数据\本地\程序\ Python的\ Python36 \ LIB \站点包\ sklearn \ model_selection_search.py” 第945行,合适 return self._fit(X,y,groups,ParameterGrid(self.param_grid))文件 “C:\用户\ jjaaae \应用程序数据\本地\程序\ Python的\ Python36 \ LIB \站点包\ sklearn \ model_selection_search.py” 第564行,在_fit中 对于parameter_iterable文件中的参数“C:\ Users \ jjaaae \ AppData \ Local \ Programs \ Python \ Python36 \ lib \ site-packages \ sklearn \ externals \ joblib \ parallel.py”, 第768行,通话 self.retrieve()文件“C:\ Users \ jjaaae \ AppData \ Local \ Programs \ Python \ Python36 \ lib \ site-packages \ sklearn \ externals \ joblib \ parallel.py”, 第719行,检索 引发异常文件“C:\ Users \ jjaaae \ AppData \ Local \ Programs \ Python \ Python36 \ lib \ site-packages \ sklearn \ externals \ joblib \ parallel.py”, 第682行,在检索中 self._output.extend(job.get(timeout = self.timeout))文件“C:\ Users \ jjaaae \ AppData \ Local \ Programs \ Python \ Python36 \ lib \ multiprocessing \ pool.py”, 第608行,在得到 提升self._value文件“C:\ Users \ jjaaae \ AppData \ Local \ Programs \ Python \ Python36 \ lib \ multiprocessing \ pool.py”, 第385行,在_handle_tasks中 put(任务)文件“C:\ Users \ jjaaae \ AppData \ Local \ Programs \ Python \ Python36 \ lib \ site-packages \ sklearn \ externals \ joblib \ pool.py”, 第371行,发送 CustomizablePickler(buffer,self._reducers).dump(obj) _pickle.PicklingError:无法pickle:内置函数上的属性查找SelectBestPercFeats失败
答案 0 :(得分:6)
pickle包需要在另一个模块中定义自定义类,然后导入。因此,创建另一个python包文件(例如transformation.py
),然后像from transformation import SelectBestPercFeats
一样导入它。这将解决酸洗错误。
答案 1 :(得分:0)
我遇到了同样的问题,但就我而言,问题是使用函数转换器,其中pickle
有时难以序列化函数。对我来说,解决方案是改用dill
,尽管它要慢一些。
答案 2 :(得分:0)
当您编码自己的转换器时,如果该转换器包含无法序列化的代码,那么如果您尝试对其进行序列化,则整个管道将无法序列化。
不仅如此,还需要进行序列化以使您的事物并行化(例如,您在n_jobs=-1
中可见)使用多个线程。
使用scikit-learn的一件坏事是每个对象都应该有其保护程序。希望有一个解决方案。它要么使您的对象可序列化(从而从外部库中删除导入的内容),要么仅执行一项工作(无线程),要么使您的对象具有一个保护程序,该保护程序将保存对象以对其进行序列化。这里将探讨第二种解决方案。
首先,这是一个问题的定义及其解决方案,取自this source:
这个问题只会在使用Scikit-Learn的某些时候浮出水面。这是无可挽回的意义:您已经对整个生产流程进行了编码,但是一旦对其进行了培训并选择了最佳模型,您就会意识到您刚刚编码的内容无法序列化。
这意味着一旦经过训练,您的管道就无法保存到磁盘,因为其中一个步骤是从使用另一种语言编码的怪异python库中导入内容和/或使用GPU资源。您的代码闻起来很奇怪,并且开始对整整一年的研究开发感到恐慌。
希望您能很好地开始编写自己的开源框架,因为在接下来的100个编码项目中您将遇到同样的情况,并且很快会有其他客户处于同样的情况,这很关键。
好吧,这是出于创建Neuraxle的共同需求。
每个步骤都负责保存自身,您应该为怪异的对象定义一个或多个自定义保护程序对象。保护程序应该:
例如,由于管道具有自己的TruncableJoblibStepSaver,因此在调用save()方法后将执行以下操作:
您不想做肮脏的代码。他们说,不要违反得墨meter耳定律。在我看来,这是最重要(且容易被忽视)的编程法则之一。 Google,我敢。违反此法则是代码库中最邪恶的根源。
我得出的结论是,在这里不违反该法律的最简洁方法是拥有一连串的储户。如果无法通过joblib进行序列化,它将使每个对象都有特殊的保护程序。整齐。因此,只要发生故障,您就可以选择为损坏的对象创建自己的序列化程序,这样,您就无需在保存时中断封装即可手动挖掘对象,这将打破Demeter的定律。
请注意,保存器在加载保存文件时也需要能够重新加载对象。我们已经写了TensorFlow Neuraxle saver。
TL; DR:您可以在Neuraxle中的任何管道上调用save()方法,如果某些步骤定义了自定义Saver,则该步骤将使用该Saver,然后再使用默认的JoblibStepSaver。
因此,您已经使用Neuraxle完成了上述操作。整齐。现在,将Neuraxle的类用于AutoML和随机搜索等。它们应该具有适当的抽象,以便使用保护程序对事物进行序列化进行并行化。必须将事物序列化才能将您的代码发送到其他python进程进行并行化。