Индивидуальный трансформатор Mixin с метками данных в sklearn

Я работаю над небольшим проектом, в котором я пытаюсь применить SMOTE "методика избыточной выборки синтетических меньшинств", где мои данные несбалансированы..

Я создал настроенный трансформатор Mixin для функции SMOTE..

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)

Я реализовал SMOTE в функции FIT, потому что не хочу, чтобы она применялась к тестовым данным.

и, к сожалению, я получил эту ошибку:

     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() Метод должен возвращать себя, а не преобразованные значения. Если вам нужно функционировать только для данных о поездах, а не для испытаний, то реализуйте 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 из пакета imblearn вместо 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))
    ])
Другие вопросы по тегам