sklearn中带有数据标签的自定义transformerMixin
Posted
技术标签:
【中文标题】sklearn中带有数据标签的自定义transformerMixin【英文标题】:customized transformerMixin with data labels in sklearn 【发布时间】:2018-09-21 02:09:08 【问题描述】:我正在做一个小项目,我正在尝试应用 SMOTE“Synthetic Minority Over-sampling Technique”,我的数据不平衡..
我为 SMOTE 函数创建了一个自定义的 transformerMixin ..
class smote(BaseEstimator, TransformerMixin):
def fit(self, X, y=None):
print(X.shape, ' ', type(X)) # (57, 28) <class 'numpy.ndarray'>
print(len(y), ' ', type) # 57 <class 'list'>
smote = SMOTE(kind='regular', n_jobs=-1)
X, y = smote.fit_sample(X, y)
return X
def transform(self, X):
return X
model = Pipeline([
('posFeat1', featureVECTOR()),
('sca1', StandardScaler()),
('smote', smote()),
('classification', SGDClassifier(loss='hinge', max_iter=1, random_state = 38, tol = None))
])
model.fit(train_df, train_df['label'].values.tolist())
predicted = model.predict(test_df)
我在 FIT 函数上实现了 SMOTE,因为我不希望它应用于测试数据..
不幸的是,我收到了这个错误:
model.fit(train_df, train_df['label'].values.tolist())
File "C:\Python35\lib\site-packages\sklearn\pipeline.py", line 248, in fit
Xt, fit_params = self._fit(X, y, **fit_params)
File "C:\Python35\lib\site-packages\sklearn\pipeline.py", line 213, in _fit
**fit_params_steps[name])
File "C:\Python35\lib\site-packages\sklearn\externals\joblib\memory.py", line 362, in __call__
return self.func(*args, **kwargs)
File "C:\Python35\lib\site-packages\sklearn\pipeline.py", line 581, in _fit_transform_one
res = transformer.fit_transform(X, y, **fit_params)
File "C:\Python35\lib\site-packages\sklearn\base.py", line 520, in fit_transform
return self.fit(X, y, **fit_params).transform(X)
AttributeError: 'numpy.ndarray' object has no attribute 'transform'
【问题讨论】:
【参考方案1】:fit()
mehtod 应该返回 self,而不是转换后的值。如果您只需要训练数据而不是测试的功能,请实现fit_transform()
方法。
class smote(BaseEstimator, TransformerMixin):
def fit(self, X, y=None):
print(X.shape, ' ', type(X)) # (57, 28) <class 'numpy.ndarray'>
print(len(y), ' ', type) # 57 <class 'list'>
self.smote = SMOTE(kind='regular', n_jobs=-1).fit(X, y)
return self
def fit_transform(self, X, y=None):
self.fit(X, y)
return self.smote.sample(X, y)
def transform(self, X):
return X
解释:在训练数据上(即当pipeline.fit()
被调用时)管道将首先尝试在内部对象上调用fit_transform()
。如果没有找到,那么它将分别调用fit()
和transform()
。
在测试数据上,每个内部对象仅调用transform()
,因此此处不应更改您提供的测试数据。
更新:上面的代码还是会报错。
您会看到,当您对提供的数据进行过采样时,X
和 y
中的样本数量都会发生变化。但管道仅适用于X
数据。它不会改变y
。因此,如果我更正上述错误,您将收到关于标签不匹配样本的错误。如果偶然生成的样本与之前的样本相等,那么y
的值也不会对应于新的样本。
可行的解决方案:真傻。
您可以使用 Pipeline from the imblearn package 代替 scikit-learn 管道。当在管道上调用fit()
时,它会自动处理re-sample
,并且不会重新采样测试数据(当调用transform()
或predict()
时)。
其实我知道 imblearn.Pipeline 处理sample()
方法,但是当你实现一个自定义类并说测试数据不能改变时被抛出。我没想到这是默认行为。
只需替换
from sklearn.pipeline import Pipeline
与
from imblearn.pipeline import Pipeline
一切就绪。无需像您那样制作自定义类。只需使用原装 SMOTE。比如:
random_state = 38
model = Pipeline([
('posFeat1', featureVECTOR()),
('sca1', StandardScaler()),
# Original SMOTE class
('smote', SMOTE(random_state=random_state)),
('classification', SGDClassifier(loss='hinge', max_iter=1, random_state=random_state, tol=None))
])
【讨论】:
你的意思是:.sample(X, y) ?另外,为什么你没有在 fit_transform 中实现 smote 而不是调用它!? @Minion 当您执行fit_sample()
时,您将两个函数连接在一起,fit()
和sample()
。我已将fit()
部分移至fit()
并仅在fit_transform()
中调用sample()
。如果需要,您可以在其中复制整个 fit()
。我这样做只是为了代码清晰。
您的代码产生错误:文件“C:\Python35\lib\site-packages\sklearn\utils\validation.py”,第 433 行,在 check_array array = np.array(array, dtype =dtype, order=order, copy=copy) ValueError: could not broadcast input array from shape (81,28) into shape (81)
@Minion 请提供您的完整代码和一些产生错误的数据样本。编辑问题以添加详细信息。
@Minion 是的,我收到了错误。我将编辑答案以添加解释。以上是关于sklearn中带有数据标签的自定义transformerMixin的主要内容,如果未能解决你的问题,请参考以下文章
在 xib 中带有可选 UIImageView 的自定义 UITableViewCell