sklearn.pipeline 中的 LeaveOneOutEncoder
LeaveOneOutEncoder in sklearn.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],}))
帮忙找错!错误一定很简单,但我的眼睛在游动。而且问题一定出在 class MyLEncoder 中。我必须改变什么?
您正在呼叫
encc = enc.fit(np.asarray(X), y)
在 MyLEncoder
的 transform()
方法中。
所以这里有几个问题:
1) 你的LeaveOneOutEncoder
只记得最后传给MyLEncoder
的transform
的数据而忘记了之前的数据。
2) 在拟合过程中 LeaveOneOutEncoder
需要 y
存在。但这在预测期间不会出现,当 MyLEncoder
transform()
被调用时。
3) 当前您的线路:
pipeline.predict(X)
能正常工作是因为你的 X
是一样的,当 MyLEncoder
transform()
被调用时,你已经定义了 y
所以它被使用了。但那是错误的。
4) 一个不相关的东西(可能不称之为错误)。当你这样做时:
pipeline.predict(pd.DataFrame({ 'y': [3, 8], 'a': ['a', 'b' ], 'b': [3, 6],}))
pipeline.predict()
只需要 X
,不需要 y
。但是您也在其中发送 y
。目前这不是问题,因为在管道中你只使用 a
列并丢弃所有信息,但也许在复杂的设置中,这可能会漏掉并且 y
列中的数据将被用作特征(X
数据)会给你错误的结果。
要解决此问题,请将您的 MyLEncoder
更改为:
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)
现在当你这样做时:
pipeline.predict(pd.DataFrame({ 'y': [3, 8], 'a': ['a', 'b' ], 'b': [3, 6],}))
你不会得到任何错误,但仍然如第 4 点所述,我希望你这样做:
new_df = pd.DataFrame({ 'y': [3, 8], 'a': ['a', 'b' ], 'b': [3, 6],})
new_X = new_df[['a', 'b']]
new_y = new_df['y']
pipeline.predict(new_X)
因此训练时间中使用的 X 和预测时间中使用的 new_X 看起来相同。
我做了如下
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
所以我在 lb
的 encc = enc.fit(np.asarray(lb), y)
行中更改了 X
。
我用 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],}))
帮忙找错!错误一定很简单,但我的眼睛在游动。而且问题一定出在 class MyLEncoder 中。我必须改变什么?
您正在呼叫
encc = enc.fit(np.asarray(X), y)
在 MyLEncoder
的 transform()
方法中。
所以这里有几个问题:
1) 你的LeaveOneOutEncoder
只记得最后传给MyLEncoder
的transform
的数据而忘记了之前的数据。
2) 在拟合过程中 LeaveOneOutEncoder
需要 y
存在。但这在预测期间不会出现,当 MyLEncoder
transform()
被调用时。
3) 当前您的线路:
pipeline.predict(X)
能正常工作是因为你的 X
是一样的,当 MyLEncoder
transform()
被调用时,你已经定义了 y
所以它被使用了。但那是错误的。
4) 一个不相关的东西(可能不称之为错误)。当你这样做时:
pipeline.predict(pd.DataFrame({ 'y': [3, 8], 'a': ['a', 'b' ], 'b': [3, 6],}))
pipeline.predict()
只需要 X
,不需要 y
。但是您也在其中发送 y
。目前这不是问题,因为在管道中你只使用 a
列并丢弃所有信息,但也许在复杂的设置中,这可能会漏掉并且 y
列中的数据将被用作特征(X
数据)会给你错误的结果。
要解决此问题,请将您的 MyLEncoder
更改为:
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)
现在当你这样做时:
pipeline.predict(pd.DataFrame({ 'y': [3, 8], 'a': ['a', 'b' ], 'b': [3, 6],}))
你不会得到任何错误,但仍然如第 4 点所述,我希望你这样做:
new_df = pd.DataFrame({ 'y': [3, 8], 'a': ['a', 'b' ], 'b': [3, 6],})
new_X = new_df[['a', 'b']]
new_y = new_df['y']
pipeline.predict(new_X)
因此训练时间中使用的 X 和预测时间中使用的 new_X 看起来相同。
我做了如下
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
所以我在 lb
的 encc = enc.fit(np.asarray(lb), y)
行中更改了 X
。