代码之家  ›  专栏  ›  技术社区  ›  Minions

在sklearn中使用数据标签定制TransformerMaxin

  •  5
  • Minions  · 技术社区  · 7 年前

    我正在做一个小项目,尝试应用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'
    
    1 回复  |  直到 6 年前
        1
  •  12
  •   Christoph H.    5 年前

    fit() 方法应该返回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() 分别地

    在测试数据上,只有 转换() 为每个内部对象调用,因此此处不应更改您提供的测试数据。

    使现代化 :上述代码仍将引发错误。 您可以看到,当您对提供的数据进行过采样时 X y 两者都会改变。但管道只能在 十、 数据它不会改变 Y 。因此,如果我更正上述错误,您可能会收到有关样本与标签不匹配的错误。如果碰巧生成的样本与以前的样本相等,则 Y 值将与新样本不对应。

    工作解决方案 :愚蠢的我。

    您可以使用 Pipeline from the imblearn package 代替scikit学习管道。它会自动注意 re-sample 调用时 fit() 在管道上,并且不重新采样测试数据(调用时 转换() predict() )。

    事实上,我知道这一点。管道句柄 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))
        ])