Pandas 如何创建自己的自定义转换器并在scikit learn中的管道中使用它们?

Pandas 如何创建自己的自定义转换器并在scikit learn中的管道中使用它们?,pandas,scikit-learn,data-science,Pandas,Scikit Learn,Data Science,我是机器学习新手,所以如果问题很傻,我的代码没有多大意义,我会提前道歉 我从kaggle下载了泰坦尼克号的数据集,希望创建一个分类器模型,根据几个重要特征预测乘客是否幸存。其中一些重要特征是: 名字 性 年龄 船舱 票 船舱 登船 以下是数据的外观: 其中一些功能的值为空,或者我想在对列进行编码之前对其进行修改(例如,名称列我只想使用字符串“Mr”、“Mrs”而不是其全名) 我知道如何通过使用正常的熊猫操作(如fillna()等)来完成所有这些操作。。。但是我想创建一个管道和一个列转换器,这样

我是机器学习新手,所以如果问题很傻,我的代码没有多大意义,我会提前道歉

我从kaggle下载了泰坦尼克号的数据集,希望创建一个分类器模型,根据几个重要特征预测乘客是否幸存。其中一些重要特征是:

  • 名字
  • 年龄
  • 船舱
  • 船舱
  • 登船
  • 以下是数据的外观:

    其中一些功能的值为空,或者我想在对列进行编码之前对其进行修改(例如,名称列我只想使用字符串“Mr”、“Mrs”而不是其全名)

    我知道如何通过使用正常的熊猫操作(如fillna()等)来完成所有这些操作。。。但是我想创建一个管道和一个列转换器,这样我就可以轻松地快速准备/处理数据,而不是重新键入相同的代码来修改数据

    对于“年龄”列中的空值,我将使用SimpleComputer用中值填充空值,对于“上船”和“船舱”,我将用“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'))
    ])
    
    在这里,我还将创建一个自定义转换器来修改名称,使其仅为“mr”、“mrs”等。。这段代码可能是错误的,我不确定我需要从transform返回什么

    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
    
    接下来,我创建一个新列,以确定具有票证Id的人员是否单独旅行:

    来自sklearn.base导入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())
    ])
    
    最后我使用了柱状变压器

    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
    
    in(x)
    8 def变换(自、X、y=无):
    9如果自行修改:
    --->10 X['Cabin']=X['Cabin']。适用(λX:X[0])
    11返回X
    TypeError:“float”对象不可下标
    
    这是因为座舱仍然具有NaN值,因此您不能下标NaN。但是在我的管道中,在运行CAB_管道之前,我应该首先使用SimpleImputer将空CAB值填充为'U'。为什么它还在这样做

    两个问题:

  • 如何编写自定义转换器,以及从transform方法返回什么
  • 为什么管道没有按顺序运行,即首先填写空值,然后访问CAB列的下标值

  • 非常感谢您的帮助

    ColumnTransformer不按顺序执行转换

    Columntransformer中的步骤应应用于特定列,而不是列上的单个转换。 若您需要在一列上进行多重转换,那个么应该首先将它们打包到管道中,然后在ColumnTransformer中运行它

    希望有帮助

    我在这里找到了一些很好的例子: