Ошибка при использовании специального преобразователя в конвейере SKLearn, но не в качестве автономного преобразователя

В качестве упражнения я пытаюсь создать собственный преобразователь, который принимает набор данных и метки и возвращает преобразованный набор данных, сохраняя только те столбцы, корреляция которых с метками превышает определенный порог. Трансформатор задается следующим кодом:

from sklearn.base import BaseEstimator, TransformerMixin

class CorrelatedAttributesKeeper(BaseEstimator, TransformerMixin):
    def __init__(self, correlation_threshold = 0.5):
        self.correlation_threshold = correlation_threshold
        self.returned_indices = []    
    def fit(self, X, y=None):
        correlations = []
        for col in X:
            correlations.append(np.corrcoef(X[col].to_numpy(), y.to_numpy())[0,1])
        for idx, x in enumerate(correlations):
            if x > self.correlation_threshold:
                self.returned_indices.append(idx)
        return self
    def transform(self, X):
        return X.iloc[:, self.returned_indices]

Кажется, что следующее работает так, как задумано:

high_correl_transformer = CorrelatedAttributesKeeper(0.5)
transformed_housing_num = high_correl_transformer.fit_transform(housing_num, housing_labels) 

Однако при попытке запустить его как часть конвейера возникают ошибки:

num_pipeline2 = Pipeline([
    ('imputer', SimpleImputer(strategy = "median")),
    ('attribs_adder', CombinedAttributesAdder()),
    ('std_scaler', StandardScaler()),
    ('correl_keeper', CorrelatedAttributesKeeper()),])
housing_num_tr2 = num_pipeline.fit_transform(housing_num, housing_labels)

Это приводит к следующей ошибке

Traceback (most recent call last):
  File "<string>", line 17, in __PYTHON_EL_eval
  File "<string>", line 3, in <module>
  File "/tmp/babel-0JUX9y/python-okiPo8", line 6, in <module>
    housing_num_tr2 = num_pipeline.fit_transform(housing_num, housing_labels)
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/sklearn/base.py", line 1474, in wrapper
    return fit_method(estimator, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/sklearn/pipeline.py", line 543, in fit_transform
    return last_step.fit_transform(
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/sklearn/utils/_set_output.py", line 295, in wrapped
    data_to_wrap = f(self, X, *args, **kwargs)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/sklearn/base.py", line 1101, in fit_transform
    return self.fit(X, y, **fit_params).transform(X)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: CorrelatedAttributesKeeper.fit() takes 1 positional argument but 3 were given

Я изо всех сил пытаюсь понять трассировку стека. В нем говорится, что функция fit требует 1 позиционный аргумент, но кажется, что для этого требуется как минимум 3, как в моем определении, так и в нижней части трассировки стека: self, X и y. Чего я не получаю?

Спасибо

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
0
60
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я не знаю, что является причиной конкретного TypeError, о котором вы сообщили, но этот ответ решает еще одну проблему с классом.

Шаги, предшествующие вашему пользовательскому преобразователю, возвращают массивы numpy, что может привести к ошибке пользовательского преобразователя, поскольку он ожидает фрейм данных pandas.

Я собирался предложить использовать StandardScaler().set_output(transform='pandas') и SimpleImputer().set_output(transform='pandas'), чтобы настроить их для возврата кадров данных, однако я думаю, что это приведет к ошибке другого пользовательского оценщика, поскольку он ожидает массивы numpy (я сослался на github примера, который вы работать с).

Вы можете изменить свой собственный преобразователь для работы с массивами numpy. Я сделал это ниже, и это работает при запуске:

make_pipeline(
    SimpleImputer(),
    StandardScaler(),
    CorrelatedAttributesKeeper()
).fit_transform(X, y)

Я также внес некоторые другие изменения, чтобы сделать его более соответствующим требованиям sklearn оценщиков. Эти изменения включают добавление завершающего подчеркивания для обозначения соответствующих атрибутов; определяющий self.n_features_in_; и не создавать новые переменные внутри __init__ (ограничьтесь только сохранением предоставленных аргументов).

Модифицированный класс:

import pandas as pd
import numpy as np
from sklearn.base import BaseEstimator, TransformerMixin
from sklearn.utils import check_array, check_X_y

class CorrelatedAttributesKeeper(BaseEstimator, TransformerMixin):
    def __init__(self, correlation_threshold=0.5):
        self.correlation_threshold = correlation_threshold
        
    def fit(self, X, y=None):
        
        #To np if necessary, and checks
        X, y = check_X_y(X, y)
            
        self.n_features_in_ = X.shape[1]
        self.returned_indices_ = []
        
        correlations = []
        
        for col_idx in range(self.n_features_in_):
            correlations.append(np.corrcoef(X[:, col_idx], y)[0,1])
        
        for idx, x in enumerate(correlations):
            if x > self.correlation_threshold:
                self.returned_indices_.append(idx)
        
        return self
    
    def transform(self, X):
        X = check_array(X)
        return X[:, self.returned_indices_]

Данные и тесты:

#
#Test data
#
np.random.seed(0)
X = pd.DataFrame({
    'f0': np.linspace(0, 1, 100),
    'f1': np.linspace(0, 1, 100) + np.random.uniform(-0.4, .4, size=100),
    'f2': np.random.normal(size=100),
    'f3': np.random.normal(size=100),
})
y = pd.Series(np.linspace(0, 1, 100))

# Estimator should return f0 and f1, but not f2 or f3
display(
    'Correlation values',
    pd.concat([X, y.to_frame()], axis=1).corr().iloc[:-1, -1]
)

#Test separately
#with dataframes
CorrelatedAttributesKeeper().fit_transform(X, y)#.returned_indices_
#with numpy arrays
CorrelatedAttributesKeeper().fit_transform(X.values, y.values)#.returned_indices_

#Test in pipeline
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.impute import SimpleImputer

make_pipeline(
    SimpleImputer(),
    StandardScaler(),
    CorrelatedAttributesKeeper()
).fit_transform(X, y)

Это хорошая точка. Но я не понимаю, как это могло привести к ошибке в вопросе?

Ben Reiniger 29.04.2024 15:55

Хорошая точка зрения. Я просмотрел это еще раз и не могу отследить источник оригинала TypeError, поэтому пояснил, что мой ответ касается другой проблемы с классом.

MuhammedYunus 29.04.2024 16:55

Другие вопросы по теме