Я новичок в машинном обучении, поэтому заранее прошу прощения, если вопрос глуп и мой код не имеет особого смысла.
Я скачал набор данных titani c из kaggle и хочу создать модель классификатора для прогнозирования выживания пассажира на основе нескольких важных функций. Некоторые из важных особенностей:
- Имя
- Пол
- Возраст
- Каюта
- Билет
- Каюта
- встал
Вот как выглядят данные:
Некоторые из этих объекты имеют пустые значения, или я хочу изменить столбец до того, как я его 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. Почему он все еще делает это?
Пара вопросов:
- Как мне написать собственные преобразователи и что я должен возвращать из метода преобразования?
- почему разве конвейер идет не по порядку, т.е. сначала заполняет пустые значения И ТОГДА получает доступ к нижнему значению столбца Cabin.
Любая помощь очень ценится!