当前位置: 首页 > 知识库问答 >
问题:

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

籍弘伟
2023-03-14

我有一个简单的sklearn类,我想作为sklearn管道的一部分使用。这个类只接受一个pandas dataframex_df和一个分类列名,并调用pd.get_dummies返回dataframe,该列被转换成一个虚拟变量矩阵...

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

现在使用这个转换器来进行FIT/Transform,我得到了预期的输出。以下是一些玩具数据:

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
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次拟合

None None None None[CV]dummy_vars__column_to_dummy=category_1,clf__penalty=l1...........

回溯(最近调用的最后一次):

文件“/home/max/anaconda3/envs/reme/lib/python2.7/site-packages/sklearn/externals/joblib/parallel.py”,第588行,在_dispatch job=self._backend.apply_async(批处理,callback=cb)中

文件“/home/max/anaconda3/envs/reme/lib/python2.7/site-packages/sklearn/externals/joblib/_parallel_backends.py”,第111行,在apply_async result=ImmediateResult(func)中

文件“/home/max/anaconda3/envs/reme/lib/python2.7/site-packages/sklearn/externals/joblib/_parallel_backends.py”,第332行,在init self中。results=batch()

文件“/home/max/anaconda3/envs/reme/lib/html" target="_blank">python2.7/site-packages/sklearn/externals/joblib/parallel.py”,第131行,调用返回[func(*args,**kwargs)for func,args,kwargs in self.items]

文件“/home/max/anaconda3/envs/reme/lib/python2.7/site-packages/sklearn/model_selection/_validation.py”,第437行,in_fit_and_score estimator.fit(X_train,y_train,**fit_params)

文件“/home/max/anaconda3/envs/reme/lib/python2.7/site-packages/sklearn/pipeline.py”,第257行,在fit Xt中,fit_params=SELF._fit(X,y,**fit_params)

文件“/home/max/anaconda3/envs/reme/lib/python2.7/site-packages/sklearn/pipeline.py”,第222行,in_fit**fit_params_steps[name])

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

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

文件“/home/max/anaconda3/envs/reme/lib/python2.7/site-packages/sklearn/base.py”,第521行,在fit_transform中返回self.fit(X,y,**fit_params).transform(X)

文件“”,第21行,在转换dummy_matrix=pd.get_dummies(x_df[column],prefix=column)中

文件“/home/max/anaconda3/envs/reme/lib/python2.7/site-packages/pandas/core/frame.py”,第1964行,在getitem中返回self._getitem_column(key)

文件“/home/max/anaconda3/envs/reme/lib/python2.7/site-packages/pandas/core/frame.py”,第1971行,在_getitem_column中返回self._get_item_cache(key)

文件“/home/max/anaconda3/envs/reme/lib/python2.7/site-packages/pandas/core/generic.py”,第1645行,在_get_item_cache values=self._data.get(item)中

文件“/home/max/anaconda3/envs/reme/lib/python2.7/site-packages/pandas/core/internals.py”,第3599行,在get raise ValueError中(“不能用空键标记索引”)

ValueError:不能用空键标记索引

共有1个答案

管景天
2023-03-14

追踪告诉你到底哪里出了问题。学习诊断跟踪确实非常有价值,尤其是当您从可能没有完全理解的库继承时。

现在,我已经在sklearn中完成了一些继承工作,我可以毫无疑问地告诉您,如果输入到fitfit_transform方法中的数据类型不是NumPy数组,gridsearchcv将会给您带来一些麻烦。正如Vivek在他的评论中提到的,传递给fit方法的X不再是一个数据frame。但我们先来看看痕迹。

ValueError:不能用空键标记索引

dummy_var_encoder(column_to_dummy=None)

这样修改__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
 类似资料:
  • 问题内容: 我正在使用JSF设置表单(这是我的新手),并且在其中一个字段上收到消息。该字段实际上是一个具有自定义转换器的单独对象(如下文所示)。 这是我所拥有的(删除了不相关的代码): 我有一堂课: 我也有一个您在该类中引用的类: 那么对于我的表格,我有: 最后,对于我的转换器,我有: 现在,当我进入表单并提交时,我将获得状态旁边的内容。我在这方面还很新,感谢@BalusC,我一直很远。 任何帮助

  • 即。在货币管道上完成一些额外的格式化。为此,我想在自定义管道的组件代码中使用现有管道。

  • 使装饰器包含具有name属性的管道元数据。 此值将用于在模板表达式中调用此管道。 它必须是有效的JavaScript标识符。 实现PipeTransform接口的transform方法。 此方法接受管道的值和任何类型的可变数量的参数,并返回一个变换的(“管道”)值。 import { Component } from '@angular/core'; selector: 'app-root',

  • 问题内容: 下面一些Groovy类中的方法由其他我不知道的其他管道脚本类调用。 所有的println语句已被logger.info取代。 log4j2-test.properties Jenkins作业控制台上的输出(下面仅显示相关部分): 我配置的记录器可能未调用 运行时实例为OutputEventListenerBackedLogger 即使我更改了logger语句,它们也不会反映在输出中,但

  • 问题内容: 我想修改Django内置模块的一些小细节。具体来说,我想要一个不同的表单,该表单将用户名作为电子邮件字段(并通过电子邮件发送备用电子邮件地址。)(我宁愿不要做任何多余的修改- 似乎 只需要简单的表单更改即可。) 当我使用自定义的时,我最终与自己的管理界面发生冲突,并收到“已注册”错误。 看来我必须创建自己的管理站点,并枚举所有模型。它只有18个类,但这似乎是一个DRY问题-每次更改都需

  • 获取频道自定义菜单 删除频道自定义菜单 设置频道自定义菜单