我正在开展一个小项目,我试图应用SMOTE"合成少数过采样技术",我的数据不平衡......
我为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'
答案 0 :(得分:4)
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 Pipeline。当在管道上调用re-sample
时,它会自动关注fit()
,并且不会重新采样测试数据(在调用transform()
或predict()
时)。
实际上我知道imblearn.Pipeline处理sample()
方法,但在实现自定义类并且说测试数据不能更改时被抛弃了。我没想到这是默认行为。
只需替换
from sklearn.pipeline import Pipeline
带
from imblearn.pipeline import Pipeline
你们都已经准备好了。不需要像你那样制作自定义课程。只需使用原装SMOTE。类似的东西:
model = Pipeline([
('posFeat1', featureVECTOR()),
('sca1', StandardScaler()),
# Original SMOTE class
('smote', SMOTE()),
('classification', SGDClassifier(loss='hinge', max_iter=1, random_state = 38, tol = None))
])