AttributeError при использовании ColumnTransformer в конвейер - PullRequest
0 голосов
/ 22 января 2019

Это мой первый проект машинного обучения, и я впервые использую ColumnTransformer. Моя цель - выполнить два этапа предварительной обработки данных и использовать ColumnTransformer для каждого из них.

На первом шаге я хочу заменить отсутствующие значения в моем фрейме данных строкой «missing_value» для некоторых функций и наиболее частым значением для остальных функций. Поэтому я объединяю эти две операции, используя ColumnTransformer и передавая ему соответствующие столбцы моего информационного кадра.

На втором шаге я хочу использовать только что обработанные данные и применять OrdinalEncoder или OneHotEncoder в зависимости от функций. Для этого я снова использую ColumnTransformer.

Затем я объединяю два этапа в один конвейер.

Я использую набор данных Kaggle Houses Price, у меня есть версия 0.20 scikit-learn, и это упрощенная версия моего кода:

cat_columns_fill_miss = ['PoolQC', 'Alley']
cat_columns_fill_freq = ['Street', 'MSZoning', 'LandContour']
cat_columns_ord = ['Street', 'Alley', 'PoolQC']
ord_mapping = [['Pave', 'Grvl'],                          # Street
               ['missing_value', 'Pave', 'Grvl'],         # Alley
               ['missing_value', 'Fa', 'TA', 'Gd', 'Ex']  # PoolQC
]
cat_columns_onehot = ['MSZoning', 'LandContour']


imputer_cat_pipeline = ColumnTransformer([
        ('imp_miss', SimpleImputer(strategy='constant'), cat_columns_fill_miss),  # fill_value='missing_value' by default
        ('imp_freq', SimpleImputer(strategy='most_frequent'), cat_columns_fill_freq),
])

encoder_cat_pipeline = ColumnTransformer([
        ('ordinal', OrdinalEncoder(categories=ord_mapping), cat_columns_ord),
        ('pass_ord', OneHotEncoder(), cat_columns_onehot),
])

cat_pipeline = Pipeline([
        ('imp_cat', imputer_cat_pipeline),
        ('cat_encoder', encoder_cat_pipeline),
])

К сожалению, когда я применяю его к housing_cat, подмножество моего информационного кадра, включающее только категориальные функции,

cat_pipeline.fit_transform(housing_cat)

Я получаю ошибку:

AttributeError: у объекта 'numpy.ndarray' нет атрибута 'столбцы'

Во время обработки вышеуказанного исключения произошло другое исключение:

...

ValueError: Указание столбцов с использованием строк поддерживается только для панд DataFrames

Я пробовал этот упрощенный конвейер, и он работает правильно:

new_cat_pipeline = Pipeline([
        ('imp_cat', imputer_cat_pipeline),
        ('onehot', OneHotEncoder()),
])

Однако, если я попытаюсь:

enc_one = ColumnTransformer([
        ('onehot', OneHotEncoder(), cat_columns_onehot),
        ('pass_ord', 'passthrough', cat_columns_ord)
])

new_cat_pipeline = Pipeline([
        ('imp_cat', imputer_cat_pipeline),
        ('onehot_encoder', enc_one),
])

Я начинаю получать ту же ошибку.

Я подозреваю, что эта ошибка связана с использованием ColumnTransformer на втором этапе, но я на самом деле не понимаю, откуда она взялась. Способ идентификации столбцов на втором шаге такой же, как на первом шаге, поэтому мне остается неясным, почему только на втором шаге я получаю ошибку атрибута ...

Ответы [ 2 ]

0 голосов
/ 13 августа 2019

Опция # 2

использовать функцию make_pipeline

(Была такая же ошибка, нашел этот ответ, чем нашел это: Представляем ColumnTransformer )

from sklearn.compose import make_column_transformer
from sklearn.pipeline import make_pipeline
cat_columns_fill_miss = ['PoolQC', 'Alley']
cat_columns_fill_freq = ['Street', 'MSZoning', 'LandContour']
cat_columns_ord = ['Street', 'Alley', 'PoolQC']
ord_mapping = [['Pave', 'Grvl'],                          # Street
               ['missing_value', 'Pave', 'Grvl'],         # Alley
               ['missing_value', 'Fa', 'TA', 'Gd', 'Ex']  # PoolQC
               ]
cat_columns_onehot = ['MSZoning', 'LandContour']

imputer_cat_pipeline = make_column_transformer(
    (make_pipeline(SimpleImputer(strategy='constant'), cat_columns_fill_miss),
    (make_pipeline(SimpleImputer(strategy='most_frequent'), cat_columns_fill_freq),
)

encoder_cat_pipeline = make_column_transformer(
    (OrdinalEncoder(categories=ord_mapping), cat_columns_ord),
    (OneHotEncoder(), cat_columns_onehot),
)

cat_pipeline = Pipeline([
    ('imp_cat', imputer_cat_pipeline),
    ('cat_encoder', encoder_cat_pipeline),
])

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

Однако, важная часть состоит в том, чтобы использовать make_pipeline вокруг SimpleImputer, чтобы правильно использовать его в конвейере:

imputer_cat_pipeline = make_column_transformer(
    (make_pipeline(SimpleImputer(strategy='constant'), cat_columns_fill_miss),
)
0 голосов
/ 22 января 2019

ColumnTransformer возвращает numpy.array, поэтому он не может иметь атрибут столбца (как указано в вашей ошибке).

Если я могу предложить другое решение, используйте pandas для обеих ваших задач, это будет проще.

Шаг 1 - замена отсутствующих значений

Чтобы заменить отсутствующее значение в подмножестве столбцов строкой missing_value, используйте следующую команду:

dataframe[["PoolQC", "Alley"]].fillna("missing_value", inplace=True)

В остальном (вменяя среднее значение для каждого столбца), это будет отлично работать:

dataframe[["Street", "MSZoning", "LandContour"]].fillna(
    dataframe[["Street", "MSZoning", "LandContour"]].mean(), inplace=True
)

Шаг 2 - одна горячая кодировка и категориальные переменные

pandas обеспечивает get_dummies, чтовозвращает pandas Dataframe, в отличие от ColumnTransfomer, код для этого будет:

encoded = pd.get_dummies(dataframe[['MSZoning', 'LandContour']], drop_first=True)
pd.dropna(['MSZoning', 'LandContour'], axis=columns, inplace=True)
dataframe = dataframe.join(encoded)

Для порядковых переменных и их кодирования я бы посоветовал вам посмотреть на этот SO-ответ (к сожалению, какое-то руководствов этом случае потребуется сопоставление).

Если вы все равно хотите использовать преобразователь

Получить np.array из кадра данных с помощью атрибута values, передать его через конвейер и воссоздать столбцы ииндексы из массива, такие как:

pd.DataFrame(data=your_array, index=np.arange(len(your_array)), columns=["A", "B"])

Хотя есть одна оговорка об этом приближении;вы не будете знать имена специально созданных столбцов с горячим кодированием (конвейер не сделает этого за вас).

Кроме того, вы можете получить имена столбцов из объектов преобразования sklearn (например, используя * 1038).* атрибут), но я думаю, что это сломает конвейер (кто-то поправит меня, если я ошибаюсь).

...