Scikit-learn: Не удается получить имена функций после ColumnTransformer

Созданный на 6 нояб. 2018  ·  13Комментарии  ·  Источник: scikit-learn/scikit-learn

Когда я использую ColumnTransformer для предварительной обработки различных столбцов (включая числовые, категории, текстовые) с конвейером, я не могу получить имена функций окончательных преобразованных данных, что трудно отладить.

Вот код:

titanic_url = ('https://raw.githubusercontent.com/amueller/'
               'scipy-2017-sklearn/091d371/notebooks/datasets/titanic3.csv')

data = pd.read_csv(titanic_url)

target = data.pop('survived')

numeric_columns = ['age','sibsp','parch']
category_columns = ['pclass','sex','embarked']
text_columns = ['name','home.dest']

numeric_transformer = Pipeline(steps=[
    ('impute',SimpleImputer(strategy='median')),
    ('scaler',StandardScaler()
    )
])
category_transformer = Pipeline(steps=[
    ('impute',SimpleImputer(strategy='constant',fill_value='missing')),
    ('ohe',OneHotEncoder(handle_unknown='ignore'))
])
text_transformer = Pipeline(steps=[
    ('cntvec',CountVectorizer())
])

preprocesser = ColumnTransformer(transformers=[
    ('numeric',numeric_transformer,numeric_columns),
    ('category',category_transformer,category_columns),
    ('text',text_transformer,text_columns[0])
])

preprocesser.fit_transform(data)
  1. preprocesser.get_feature_names() получит ошибку:
    AttributeError: Transformer numeric (type Pipeline) does not provide get_feature_names.
  2. В ColumnTransformertext_transformer может обрабатывать только строку (например, 'Sex'), но не список строк как text_columns

Самый полезный комментарий

Это не проблема ColumnTransformer.

  1. это о трубопроводе. Обратите внимание, что eli5 реализует функцию имен функций, которая может поддерживать конвейер.

Касательно 2. Возможно, вы правы в том, что у нас нет чистого способа применить векторизатор текста к каждому столбцу. Я не уверен, как этого можно добиться, если мы просто не начнем поддерживать несколько столбцов ввода в CountVectorizer и т. Д.

Спасибо за любезный ответ!
Насколько я знаю, когда я предварительно обрабатываю столбец с использованием методов, которые могут изменить один столбец на несколько столбцов, таких как OneHotEncoder , CountVectorizer , я могу получить новые имена столбцов данных из преобразователя последнего шага конвейера, функция get_feature_names при использовании методов, которые не создают новые столбцы, может просто установить имя исходных столбцов.

def get_column_names_from_ColumnTransformer(column_transformer):    
    col_name = []
    for transformer_in_columns in column_transformer.transformers_[:-1]:#the last transformer is ColumnTransformer's 'remainder'
        raw_col_name = transformer_in_columns[2]
        if isinstance(transformer_in_columns[1],Pipeline): 
            transformer = transformer_in_columns[1].steps[-1][1]
        else:
            transformer = transformer_in_columns[1]
        try:
            names = transformer.get_feature_names()
        except AttributeError: # if no 'get_feature_names' function, use raw column name
            names = raw_col_name
        if isinstance(names,np.ndarray): # eg.
            col_name += names.tolist()
        elif isinstance(names,list):
            col_name += names    
        elif isinstance(names,str):
            col_name.append(names)
    return col_name

Используя приведенный выше код, я могу получить имена столбцов preprocesser .
Этот код решает этот вопрос?
Что касается eli5, я не нахожу эту функцию. Можете ли вы дать мне ссылку на явный пример или api для eli5?

Все 13 Комментарий

Это не проблема ColumnTransformer.

  1. это о трубопроводе. Обратите внимание, что eli5 реализует функцию имен функций, которая может поддерживать конвейер.

Касательно 2. Возможно, вы правы в том, что у нас нет чистого способа применить векторизатор текста к каждому столбцу. Я не уверен, как этого можно добиться, если мы просто не начнем поддерживать несколько столбцов ввода в CountVectorizer и т. Д.

Это не проблема ColumnTransformer.

  1. это о трубопроводе. Обратите внимание, что eli5 реализует функцию имен функций, которая может поддерживать конвейер.

Касательно 2. Возможно, вы правы в том, что у нас нет чистого способа применить векторизатор текста к каждому столбцу. Я не уверен, как этого можно добиться, если мы просто не начнем поддерживать несколько столбцов ввода в CountVectorizer и т. Д.

Спасибо за любезный ответ!
Насколько я знаю, когда я предварительно обрабатываю столбец с использованием методов, которые могут изменить один столбец на несколько столбцов, таких как OneHotEncoder , CountVectorizer , я могу получить новые имена столбцов данных из преобразователя последнего шага конвейера, функция get_feature_names при использовании методов, которые не создают новые столбцы, может просто установить имя исходных столбцов.

def get_column_names_from_ColumnTransformer(column_transformer):    
    col_name = []
    for transformer_in_columns in column_transformer.transformers_[:-1]:#the last transformer is ColumnTransformer's 'remainder'
        raw_col_name = transformer_in_columns[2]
        if isinstance(transformer_in_columns[1],Pipeline): 
            transformer = transformer_in_columns[1].steps[-1][1]
        else:
            transformer = transformer_in_columns[1]
        try:
            names = transformer.get_feature_names()
        except AttributeError: # if no 'get_feature_names' function, use raw column name
            names = raw_col_name
        if isinstance(names,np.ndarray): # eg.
            col_name += names.tolist()
        elif isinstance(names,list):
            col_name += names    
        elif isinstance(names,str):
            col_name.append(names)
    return col_name

Используя приведенный выше код, я могу получить имена столбцов preprocesser .
Этот код решает этот вопрос?
Что касается eli5, я не нахожу эту функцию. Можете ли вы дать мне ссылку на явный пример или api для eli5?

Что касается eli5, см. Transform_feature_names (используется объяснением_весов)

1 - это дубликат # 6425, верно? Я хочу написать об этом сон.
Я думаю, что поддержка нескольких текстовых столбцов довольно проста с помощью ColumnTransformer . Это не самый красивый код, но вы можете просто добавить CountVectorizer для каждого текстового столбца.

И ваш фрагмент на самом деле не решает проблему, потому что отсутствие get_feature_names не означает, что вы можете просто использовать имена столбцов.

1 - это дубликат # 6425, верно? Я хочу написать об этом сон.
Я думаю, что поддержка нескольких текстовых столбцов довольно проста с помощью ColumnTransformer . Это не самый красивый код, но вы можете просто добавить CountVectorizer для каждого текстового столбца.

И ваш фрагмент на самом деле не решает проблему, потому что отсутствие get_feature_names не означает, что вы можете просто использовать имена столбцов.

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

хорошо, закрываю как дубликат.

Это не проблема ColumnTransformer.

  1. это о трубопроводе. Обратите внимание, что eli5 реализует функцию имен функций, которая может поддерживать конвейер.

Касательно 2. Возможно, вы правы в том, что у нас нет чистого способа применить векторизатор текста к каждому столбцу. Я не уверен, как этого можно добиться, если мы просто не начнем поддерживать несколько столбцов ввода в CountVectorizer и т. Д.

Спасибо за любезный ответ!
Насколько я знаю, когда я предварительно обрабатываю столбец с использованием методов, которые могут изменить один столбец на несколько столбцов, таких как OneHotEncoder , CountVectorizer , я могу получить новые имена столбцов данных из преобразователя последнего шага конвейера, функция get_feature_names при использовании методов, которые не создают новые столбцы, может просто установить имя исходных столбцов.

def get_column_names_from_ColumnTransformer(column_transformer):    
    col_name = []
    for transformer_in_columns in column_transformer.transformers_[:-1]:#the last transformer is ColumnTransformer's 'remainder'
        raw_col_name = transformer_in_columns[2]
        if isinstance(transformer_in_columns[1],Pipeline): 
            transformer = transformer_in_columns[1].steps[-1][1]
        else:
            transformer = transformer_in_columns[1]
        try:
            names = transformer.get_feature_names()
        except AttributeError: # if no 'get_feature_names' function, use raw column name
            names = raw_col_name
        if isinstance(names,np.ndarray): # eg.
            col_name += names.tolist()
        elif isinstance(names,list):
            col_name += names    
        elif isinstance(names,str):
            col_name.append(names)
    return col_name

Используя приведенный выше код, я могу получить имена столбцов preprocesser .
Этот код решает этот вопрос?
Что касается eli5, я не нахожу эту функцию. Можете ли вы дать мне ссылку на явный пример или api для eli5?

Я сделал небольшое улучшение, чтобы вернуть имя типа rawname_value для форм onehot:

def get_column_names_from_ColumnTransformer(column_transformer):    
    col_name = []
    for transformer_in_columns in column_transformer.transformers_[:-1]:#the last transformer is ColumnTransformer's 'remainder'
        raw_col_name = transformer_in_columns[2]
        raw_col_name_reverse = raw_col_name[::-1]
        if isinstance(transformer_in_columns[1],Pipeline): 
            transformer = transformer_in_columns[1].steps[-1][1]
        else:
            transformer = transformer_in_columns[1]
        try:
            names = transformer.get_feature_names()
            exchange_name = [(_.split("_")) for _ in preprocessor.transformers_[:-1][0][1].steps[-1][1].get_feature_names()]
            last_pre_name = ""
            last_raw_name = ""
            for pre_name,value in exchange_name:
                if pre_name==last_pre_name:
                    col_name.append(last_raw_name+"_"+value)
                if pre_name!=last_pre_name:
                    last_pre_name=pre_name
                    last_raw_name=raw_col_name_reverse.pop()
                    col_name.append(last_raw_name+"_"+value)
        except AttributeError: # if no 'get_feature_names' function, use raw column name
            names = raw_col_name
        if isinstance(names,np.ndarray): # eg.
            col_name += names.tolist()
        elif isinstance(names,list):
            col_name += names    
        elif isinstance(names,str):
            col_name.append(names)
    return col_name

Это не проблема ColumnTransformer.

  1. это о трубопроводе. Обратите внимание, что eli5 реализует функцию имен функций, которая может поддерживать конвейер.

Касательно 2. Возможно, вы правы в том, что у нас нет чистого способа применить векторизатор текста к каждому столбцу. Я не уверен, как этого можно добиться, если мы просто не начнем поддерживать несколько столбцов ввода в CountVectorizer и т. Д.

Спасибо за любезный ответ!
Насколько я знаю, когда я предварительно обрабатываю столбец с использованием методов, которые могут изменить один столбец на несколько столбцов, таких как OneHotEncoder , CountVectorizer , я могу получить новые имена столбцов данных из преобразователя последнего шага конвейера, функция get_feature_names при использовании методов, которые не создают новые столбцы, может просто установить имя исходных столбцов.

def get_column_names_from_ColumnTransformer(column_transformer):    
    col_name = []
    for transformer_in_columns in column_transformer.transformers_[:-1]:#the last transformer is ColumnTransformer's 'remainder'
        raw_col_name = transformer_in_columns[2]
        if isinstance(transformer_in_columns[1],Pipeline): 
            transformer = transformer_in_columns[1].steps[-1][1]
        else:
            transformer = transformer_in_columns[1]
        try:
            names = transformer.get_feature_names()
        except AttributeError: # if no 'get_feature_names' function, use raw column name
            names = raw_col_name
        if isinstance(names,np.ndarray): # eg.
            col_name += names.tolist()
        elif isinstance(names,list):
            col_name += names    
        elif isinstance(names,str):
            col_name.append(names)
    return col_name

Используя приведенный выше код, я могу получить имена столбцов preprocesser .
Этот код решает этот вопрос?
Что касается eli5, я не нахожу эту функцию. Можете ли вы дать мне ссылку на явный пример или api для eli5?

Как насчет того, чтобы применить simpleimputer с add_indicator в конвейере? Такой подход не сработает.

Как насчет того, чтобы применить simpleimputer с add_indicator в конвейере? Такой подход не сработает.

Было бы неплохо иметь метод get_feature_names для этой конфигурации.

Как насчет того, чтобы применить simpleimputer с add_indicator в конвейере? Такой подход не сработает.

Вот мой вклад в краткосрочное решение. Он приводит все различные типы массивов к спискам и обрабатывает случай SimpleImputer (add_indicate = True). Это также немного более многословно.

def get_column_names_from_ColumnTransformer(column_transformer):    
    col_name = []

    for transformer_in_columns in column_transformer.transformers_[:-1]: #the last transformer is ColumnTransformer's 'remainder'
        print('\n\ntransformer: ', transformer_in_columns[0])

        raw_col_name = list(transformer_in_columns[2])

        if isinstance(transformer_in_columns[1], Pipeline): 
            # if pipeline, get the last transformer
            transformer = transformer_in_columns[1].steps[-1][1]
        else:
            transformer = transformer_in_columns[1]

        try:
          if isinstance(transformer, OneHotEncoder):
            names = list(transformer.get_feature_names(raw_col_name))

          elif isinstance(transformer, SimpleImputer) and transformer.add_indicator:
            missing_indicator_indices = transformer.indicator_.features_
            missing_indicators = [raw_col_name[idx] + '_missing_flag' for idx in missing_indicator_indices]

            names = raw_col_name + missing_indicators

          else:
            names = list(transformer.get_feature_names())

        except AttributeError as error:
          names = raw_col_name

        print(names)    

        col_name.extend(names)

    return col_name

К вашему сведению, я написал код и блог о том, как извлекать имена функций из сложных конвейеров и преобразователей столбцов. Код является улучшением по сравнению с моим предыдущим постом. https://towardsdatascience.com/extracting-plotting-feature-names-importance-from-scikit-learn-pipelines-eb5bfa6a31f4

@kylegilde Отличная статья и спасибо за код. Работает как шарм. Для глобальных объяснений я несколько часов боролся с KernelSHAP и алиби, но не смог заставить мой onehot преобразователь работать без handle_unkown='ignore'

Вот еще одна версия фрагмента @pjgao , которая включает столбцы из напоминания:

def get_columns_from_transformer(column_transformer, input_colums):    
    col_name = []

    for transformer_in_columns in column_transformer.transformers_[:-1]: #the last transformer is ColumnTransformer's 'remainder'
        raw_col_name = transformer_in_columns[2]
        if isinstance(transformer_in_columns[1],Pipeline): 
            transformer = transformer_in_columns[1].steps[-1][1]
        else:
            transformer = transformer_in_columns[1]
        try:
            names = transformer.get_feature_names(raw_col_name)
        except AttributeError: # if no 'get_feature_names' function, use raw column name
            names = raw_col_name
        if isinstance(names,np.ndarray): # eg.
            col_name += names.tolist()
        elif isinstance(names,list):
            col_name += names    
        elif isinstance(names,str):
            col_name.append(names)

    [_, _, reminder_columns] = column_transformer.transformers_[-1]

    for col_idx in reminder_columns:
        col_name.append(input_colums[col_idx])

    return col_name

Что вы думаете о добавлении аналогичной функции в основную кодовую базу?

Была ли эта страница полезной?
0 / 5 - 0 рейтинги