sklearn.pipeline中的LeaveOneOutEncoder

时间:2018-09-16 18:16:47

标签: python pipeline

我使用LeaveOneOutEncoder制作了一条管道。当然我用一个玩具的例子。 Leave One Out用于转换类别变量

import pandas as pd
import numpy as np
from sklearn import preprocessing
import sklearn
from sklearn.pipeline import Pipeline
from sklearn.pipeline import FeatureUnion
from category_encoders import  LeaveOneOutEncoder
from sklearn import linear_model
from sklearn.base import BaseEstimator, TransformerMixin

df= pd.DataFrame({ 'y': [1,2,3,4,5,6,7,8], 'a': ['a', 'b','a', 'b','a', 'b','a', 'b' ], 'b': [5,5,3,4,8,6,7,3],})

class ItemSelector(BaseEstimator, TransformerMixin):
def __init__(self, key):
    self.key = key
def fit(self, x, y=None):
    return self
def transform(self, data_dict):
    return data_dict[self.key]

class MyLEncoder(BaseEstimator, TransformerMixin):
def transform(self, X, **fit_params):
    enc = LeaveOneOutEncoder()
    encc = enc.fit(np.asarray(X), y)
    enc_data = encc.transform(np.asarray(X))
    return enc_data
def fit_transform(self, X,y=None,  **fit_params):
    self.fit(X,y,  **fit_params)
    return self.transform(X)
def fit(self, X, y, **fit_params):
    return self


X = df[['a', 'b']]
y = df['y']

regressor = linear_model.SGDRegressor()

pipeline = Pipeline([

    # Use FeatureUnion to combine the features
    ('union', FeatureUnion(
        transformer_list=[


             # categorical
            ('categorical', Pipeline([
                ('selector', ItemSelector(key='a')),
                ('one_hot', MyLEncoder())

            ])),
             # year

        ])),
    # Use a regression
    ('model_fitting', linear_model.SGDRegressor()),
])

pipeline.fit(X, y)
pipeline.predict(X)

这就是我在火车和测试数据上使用它的全部正确方法!但是当我尝试预测新数据时,我得到了错误答案

pipeline.predict(pd.DataFrame({ 'y': [3, 8], 'a': ['a', 'b' ], 'b': [3, 6],}))

帮助发现错误!错误一定很简单,但是我的眼睛在游泳。问题必须出在MyLEncoder类中。我必须改变什么?

2 个答案:

答案 0 :(得分:1)

您正在呼叫

encc = enc.fit(np.asarray(X), y)

transform()的{​​{1}}方法中。

所以这里有两个问题:

1)您的MyLEncoder只记住传递到LeaveOneOutEncoder的{​​{1}}的最后数据,而忘记先前的数据。

2)在拟合期间,transform要求MyLEncoder出现。但这在调用LeaveOneOutEncoder y的预测过程中不会出现。

3)当前您所在的行:

MyLEncoder

运气不错,因为您的transform()是相同的,并且在调用pipeline.predict(X) X时,您已经定义了MyLEncoder以便使用。但这就是错误的。

4)无关的事物(可能不会将此称为错误)。当您这样做时:

transform()

y仅需要pipeline.predict(pd.DataFrame({ 'y': [3, 8], 'a': ['a', 'b' ], 'b': [3, 6],})) ,而不需要pipeline.predict()。但是您也在其中发送X。当前这不是问题,因为在管道中您仅使用y列并丢弃所有信息,但是在复杂的设置中,这可能会漏掉,而y列中的数据将用作功能(a数据)会给您错误的结果。

要解决此问题,请将您的y更改为:

X

现在,当您执行此操作时:

MyLEncoder

您不会收到任何错误,但是仍然要注意第4点,我希望您这样做:

class MyLEncoder(BaseEstimator, TransformerMixin):

    # Save the enc during fitting
    def fit(self, X, y, **fit_params):
        enc = LeaveOneOutEncoder()
        self.enc = enc.fit(np.asarray(X), y)

        return self

    # Here, no new learning should be done, so never call fit() inside this
    # Only use the already saved enc here
    def transform(self, X, **fit_params):

        enc_data = self.enc.transform(np.asarray(X))
        return enc_data

    # No need to define this function, if you are not doing any optimisation in it.
    # It will be automatically inherited from TransformerMixin
    # I have only kept it here, because you kept it.
    def fit_transform(self, X,y=None, **fit_params):
        self.fit(X, y, **fit_params)
        return self.transform(X)

使训练时间中使用的X和预测时间中使用的new_X出现相同。

答案 1 :(得分:1)

我已经完成了以下操作

lb = df['a']
class MyLEncoder(BaseEstimator, TransformerMixin):
def transform(self, X, **fit_params):
    enc = LeaveOneOutEncoder()
    encc = enc.fit(np.asarray(lb), y)
    enc_data = encc.transform(np.asarray(X))

    return enc_data

def fit_transform(self, X,y=None,  **fit_params):
    self.fit(X,y,  **fit_params)
    return self.transform(X)

def fit(self, X, y, **fit_params):
    return self

因此,我在X的{​​{1}}行中更改了encc = enc.fit(np.asarray(lb), y)