Как мне создать свои собственные преобразователи и использовать их в конвейере в scikit-learn? - PullRequest
0 голосов
/ 12 марта 2020

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

Я скачал набор данных titani c из kaggle и хочу создать модель классификатора для прогнозирования выживания пассажира на основе нескольких важных функций. Некоторые из важных особенностей:

  1. Имя
  2. Пол
  3. Возраст
  4. Каюта
  5. Билет
  6. Каюта
  7. встал

Вот как выглядят данные:

enter image description here

Некоторые из этих объекты имеют пустые значения, или я хочу изменить столбец до того, как я его one_hot_encode (например, столбец имени, я хочу просто иметь строку «Mr», «Mrs» вместо их полного имени)

Я знаю, как сделать все это, просто используя обычные операции pandas, то есть fillna () et c ... Но я хочу создать конвейер и преобразователь столбцов, чтобы я мог быстро подготовить / обработать данные, а не перепечатывать заново тот же код для изменения данных.

Для пустых значений в столбцах «Возраст» я буду использовать SimpleImputer для заполнения пустых значений медианой, а для «Отправленных» и «Кабины» я буду заполните их значения 'U':

from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer

# Fill empty age values with median
median_pipeline = Pipeline([
    ('imputer', SimpleImputer(strategy='median'))
])

# Fill cabin and embarked with 'U'
fill_pipeline = Pipeline([
    ('fill_U', SimpleImputer(strategy='constant', fill_value='U'))
])

Здесь я также создам собственный преобразователь для m odify имена, так что это будут только 'mr', 'mrs' et c .. Этот код, вероятно, неправильный, я не уверен, что мне нужно возвращать здесь из преобразования?

from sklearn.base import BaseEstimator, TransformerMixin

class change_name(BaseEstimator, TransformerMixin):
    def __init__(self, modify_name=True):
        self.modify_name = modify_name
    def fit(self, X,y=None):
        return self
    def transform(self, X, y=None):
        if self.modify_name:
            X['Name'] = X['Name'].apply(lambda x: x.split()[1].replace('.', ''))

        return X

Затем я создаю новый столбец, чтобы определить, путешествует ли этот человек с идентификатором билета один:

из sklearn.base import BaseEstimator, TransformerMixin

class create_multiple_ticket(BaseEstimator, TransformerMixin):
    tickets = {}
    for ticket, num in X.Ticket.value_counts().items():
        if num > 1:
            tickets[ticket] = 1

    def __init__(self, change=True):
        self.change=True
        self.tickets = tickets
    def fit(self, X, y=None):
        return self
    def transform(self, X, y=None):
        if self.change:
            # Creating a new column of boolean values
            X['multiple_tickets'] = X['Ticket'].apply(lambda x: x in tickets)
        return X.drop('Ticket', axis=1)

Далее я просто получаю индекс кабины быть только одной буквой.

class modify_cabin(BaseEstimator, TransformerMixin):
    def __init__(self, modify=True):
        self.modify = True
    def fit(self, X, y=None):
        return self
    def transform(self, X, y=None):
        if self.modify:
            X['Cabin'] = X['Cabin'].apply(lambda x: x[0])
        return X

Наконец, я создаю свои конвейеры.

ticket_pipeline = Pipeline([
    ('modify_ticket', create_multiple_ticket()) 
])

name_pipeline = Pipeline([
    ('modify_name', change_name())
])

cabin_pipeline = Pipeline([
    ('modify_cabin', modify_cabin())
])

Наконец, я использую ColumnTransformer

from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import OneHotEncoder

median_attributes = ['Age']
fill_attributes = ['Cabin', 'Embarked']

onehot_encoded_attributes = ['Cabin', 'Name', 'Embarked', 'Sex']

full_pipeline = ColumnTransformer([
    ('age', median_pipeline, median_attributes), # fill empty values with age median
    ('fill', fill_pipeline, fill_attributes), # fill 'Cabin' and 'Embarked' with 'U value'
    ('name', name_pipeline, ['Name']), # Converts name column to just 'Mr', 'Miss' etc...
    ('ticket', ticket_pipeline, ['Ticket']), # Creates a new column called multiple tickets and returns true or false
    ('cabin', cabin_pipeline, ['Cabin']), # Cabin column gets modified to just one letter.
    ('categorical', OneHotEncoder(), onehot_encoded_attributes) # One_hot encodes the attributes
], remainder='passthrough')




X_train_prepared = full_pipeline.fit_transform(X_train)
X_train_prepared

Теперь, когда я запускаю код выше Я получаю следующую ошибку:

<ipython-input-68-a83b52eb52ee> in <lambda>(x)
      8     def transform(self, X, y=None):
      9         if self.modify:
---> 10             X['Cabin'] = X['Cabin'].apply(lambda x: x[0])
     11         return X

TypeError: 'float' object is not subscriptable

Это связано с тем, что в каюте по-прежнему сохраняются значения NaN, поэтому нельзя использовать индекс NaN. Но в моем конвейере я должен сначала заполнить пустые значения Cabin символом «U», используя «SimpleImputer», перед тем как будет работать cab_pipeline. Почему он все еще делает это?

Пара вопросов:

  1. Как мне написать собственные преобразователи и что я должен возвращать из метода преобразования?
  2. почему разве конвейер идет не по порядку, т.е. сначала заполняет пустые значения И ТОГДА получает доступ к нижнему значению столбца Cabin.

Любая помощь очень ценится!

1 Ответ

0 голосов
/ 12 марта 2020

ColumnTransformer не выполняет преобразования по порядку.

Шаги в Columntransformer должны применяться к отдельным столбцам, а не к отдельным преобразованиям в столбцах. Если вам нужно преобразование нескольких строк в одном столбце, вы должны сначала упаковать их в конвейер, а затем запустить в ColumnTransformer.

Надеюсь, это поможет!

Я нашел несколько хороших примеров: https://towardsdatascience.com/using-columntransformer-to-combine-data-processing-steps-af383f7d5260

...