自定义Sklearn转换器单独工作,在管道中使用时抛出错误



我有一个简单的sklearn类,我想用作sklearn管道的一部分。这个类只需要一个pandas数据帧X_DF和一个分类列名,并调用pd.get_dummies来返回数据帧,其中列变成了一个伪变量矩阵。。。

import pandas as pd
from sklearn.base import TransformerMixin, BaseEstimator
class dummy_var_encoder(TransformerMixin, BaseEstimator):
'''Convert selected categorical column to (set of) dummy variables    
'''

def __init__(self, column_to_dummy='default_col_name'):
self.column = column_to_dummy
print self.column
def fit(self, X_DF, y=None):
return self 
def transform(self, X_DF):
''' Update X_DF to have set of dummy-variables instead of orig column'''        
# convert self-attribute to local var for ease of stepping through function
column = self.column
# add columns for new dummy vars, and drop original categorical column
dummy_matrix = pd.get_dummies(X_DF[column], prefix=column)
new_DF = pd.concat([X_DF[column], dummy_matrix], axis=1)
return new_DF

现在使用这个转换器来适应/转换,我得到了预期的输出。对于以下一些玩具数据:

from sklearn import datasets
# Load toy data 
iris = datasets.load_iris()
X = pd.DataFrame(iris.data, columns = iris.feature_names)
y = pd.Series(iris.target, name='y')
# Create Arbitrary categorical features
X['category_1'] = pd.cut(X['sepal length (cm)'], 
bins=3, 
labels=['small', 'medium', 'large'])
X['category_2'] = pd.cut(X['sepal width (cm)'], 
bins=3, 
labels=['small', 'medium', 'large'])

我的伪编码器产生正确的输出:

encoder = dummy_var_encoder(column_to_dummy = 'category_1')
encoder.fit(X)
encoder.transform(X).iloc[15:21,:]
category_1
category_1  category_1_small  category_1_medium  category_1_large
15     medium                 0                  1                 0
16      small                 1                  0                 0
17      small                 1                  0                 0
18     medium                 0                  1                 0
19      small                 1                  0                 0
20      small                 1                  0                 0

然而,当我从下面定义的sklearn管道调用相同的转换器时:

from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import Pipeline
from sklearn.model_selection import KFold, GridSearchCV
# Define Pipeline
clf = LogisticRegression(penalty='l1')
pipeline_steps = [('dummy_vars', dummy_var_encoder()),
('clf', clf)
]
pipeline = Pipeline(pipeline_steps)
# Define hyperparams try for dummy-encoder and classifier
# Fit 4 models - try dummying category_1 vs category_2, and using l1 vs l2 penalty in log-reg
param_grid = {'dummy_vars__column_to_dummy': ['category_1', 'category_2'],
'clf__penalty': ['l1', 'l2']
}
# Define full model search process 
cv_model_search = GridSearchCV(pipeline, 
param_grid, 
scoring='accuracy', 
cv = KFold(),
refit=True,
verbose = 3) 

一切都很好,直到我安装好管道,在这一点上,我从伪编码器得到了一个错误:

cv_model_search.fit(X,y=y)

在[101]中:cv_model_search.fit(X,y=y)为4个中的每一个拟合3个折叠候选,共12个符合

无无无无[CV]dummy_vars_column_to_dummy=类别_1,clf_penalty=l1。。。。。。。。。

追踪(最近一次通话):

文件",第1行,在cv_model_search.fit(X,y=y)

文件"/home/max/anaconda3/envs/remine/lib/python2.7/site packages/sklearn/model_selection/_sarch.py",638线,合适cv.分割(X,y,组))

文件"/home/max/anaconda3/envs/remine/lib/python2.7/site packages/sklearn/externals/joblib/pparallel.py",第779行,在调用时self.dispatch_one_batch(迭代器):

文件"/home/max/anaconda3/envs/remine/lib/python2.7/site packages/sklearn/externals/joblib/pparallel.py",第625行,在dispatch_one_batch中自我_调度(任务)

文件"/home/max/anaconda3/envs/remine/lib/python2.7/site packages/sklearn/externals/joblib/pparallel.py",第588行,在_dispatch中job=自我_backend.apply_async(批处理,回调=cb)

文件"/home/max/anaconda3/envs/remine/lib/python2.7/site packages/sklearn/externals/joblib/\parallel_backends.py",第111行,在apply_async中result=即时结果(func)

文件"/home/max/anaconda3/envs/remine/lib/python2.7/site packages/sklearn/externals/joblib/\parallel_backends.py",第332行,在initself.results=batch()中

文件"/home/max/anaconda3/envs/remine/lib/python2.7/site packages/sklearn/externals/joblib/pparallel.py",第131行,在调用中返回[func(*args,**kwargs)for func,args,kwargs in self.items]

文件"/home/max/anaconda3/envs/remine/lib/python2.7/site packages/skmearl/model_selection/_validation.py",第437行,在_fit_and_score中估计器.fit(X_train,y_train,**fit_params)

文件"/home/max/anaconda3/envs/remine/lib/python2.7/site packages/skmear/pipeline.py",线257,配合Xt,fit_params=自身_拟合(X,y,**fit_params)

文件"/home/max/anaconda3/envs/remine/lib/python2.7/site packages/skmear/pipeline.py",第222行,in_fit**fit_params_steps[名称])

文件"/home/max/anaconda3/envs/remine/lib/python2.7/site packages/sklearn/externals/joblib/memory.py",第362行,在调用中返回self.func(*args,**kwargs)

文件"/home/max/anaconda3/envs/remine/lib/python2.7/site packages/skmear/pipeline.py",第589行,在_fit_transform_one中res=transformer.fit_transform(X,y,**fit_params)

文件"/home/max/anaconda3/envs/remine/lib/python2.7/site packages/skmear/base.py",第521行,在fit_transform中return self.fit(X,y,**fit_params).transform(X)

文件",第21行,在转换中dummy_matrix=pd.get_dummies(X_DF[列],前缀=列)

文件"/home/max/anaconda3/envs/remine/lib/python2.7/site packages/pandas/core/frame.py",第1964行,getitem返回self_getitem_column(key)

文件"/home/max/anaconda3/envs/remine/lib/python2.7/site packages/pandas/core/frame.py",第1971行,在_getitem_column中回归自我_get_item_cache(密钥)

文件"/home/max/anaconda3/envs/remine/lib/python2.7/site packages/pandas/core/generic.py",第1645行,在_get_item_cache中values=self_data.get(item)

文件"/home/max/anaconda3/envs/remine/lib/python2.7/site packages/pandas/core/internals.py",第3599行,在getraise ValueError("不能用空键标记索引")

ValueError:无法使用空键标记索引

跟踪会告诉您到底出了什么问题。学习诊断跟踪确实非常宝贵,尤其是当您从可能不完全了解的库中继承时。

现在,我自己已经在sklearn中进行了一些继承,我可以毫无疑问地告诉您,如果输入到fitfit_transform方法的数据类型不是NumPy数组,那么GridSearchCV会给您带来一些麻烦。正如Vivek在他的评论中提到的,传递给您的拟合方法的X不再是DataFrame。但让我们先来看看痕迹。

ValueError:不能用空键标记索引

虽然Vivek对NumPy数组的看法是正确的,但这里还有另一个问题。您得到的实际错误是拟合方法中column的值为None。如果您查看上面的encoder对象,您会看到__repr__方法输出以下内容:

dummy_var_encoder(column_to_dummy=None)

使用Pipeline时,此参数将被初始化并传递给GridSearchCV。这种行为在整个交叉验证和搜索方法中都可以看到,输入参数中具有不同名称的属性会导致类似的问题。解决这个问题会让你走上正确的道路。

修改__init__方法将解决这个特定问题:

def __init__(self, column='default_col_name'):
self.column = column
print(self.column)

然而,一旦你做到了这一点,Vivek提到的问题就会引起人们的注意,你将不得不处理这个问题。这是我以前遇到过的事情,尽管不是专门针对DataFrames的。我在使用sklearnGridSearchCV中提出了一个关于自定义类的解决方案,该类的fit方法需要3个参数。基本上,我创建了一个实现__getitem__方法的包装器,使数据的外观和行为能够通过GridSearchCVPipeline和其他交叉验证方法中使用的验证方法。

编辑

我做了这些更改,看起来您的问题来自验证方法check_array。虽然用dtype=pd.DataFrame调用此方法可以工作,但线性模型用dtype=np.float64调用此方法会抛出错误。要绕过这一点,而不是将原始数据与虚设数据连接起来,您只需返回虚设列并使用它们进行拟合即可。无论如何都应该这样做,因为您不希望在试图拟合的模型中同时包含伪列和原始数据。你也可以考虑drop_first选项,但我偏离主题了。因此,像这样更改fit方法可以使整个过程按预期工作。

def transform(self, X_DF):
''' Update X_DF to have set of dummy-variables instead of orig column'''        
# convert self-attribute to local var for ease of stepping through function
column = self.column
# add columns for new dummy vars, and drop original categorical column
dummy_matrix = pd.get_dummies(X_DF[column], prefix=column)
return dummy_matrix

相关内容

  • 没有找到相关文章

最新更新