You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义FeatureUnion调用get_feature_names返回异常如何解决

问题根因

出现错误输出的核心原因有两个:

  • 自定义的NameLengthTransformer、DomainLengthTransformer中get_feature_names()方法返回值是字符串类型,不符合scikit-learn的接口约定:该方法需要返回特征名构成的列表。FeatureUnion聚合特征名时会将字符串作为可迭代对象逐字符遍历,给每个字符拼接[转换器名]__前缀,最终生成了你看到的单字符拼接的错误结果。
  • EmailTransformer直接调用FeatureUnion自带的get_feature_names()方法,该方法默认会给所有子特征名加上转换器名前缀,不符合你要的输出格式;同时原代码中EmailTransformer的fit方法没有拟合内部的FeatureUnion实例,存在未初始化的隐患。
修正方案

按以下规则调整代码即可:

  1. 所有子转换器的get_feature_names()统一返回特征名列表,而非单个字符串
  2. 在EmailTransformer的fit方法中调用内部FeatureUnion的fit方法完成初始化
  3. 重写EmailTransformer的get_feature_names()逻辑,遍历内部所有子转换器,收集各转换器返回的特征名拼成平级列表,不额外添加前缀
修正后可运行代码
import re
import numpy as np
import pandas as pd
from sklearn.base import BaseEstimator, TransformerMixin
from sklearn.pipeline import FeatureUnion

def get_email_name(email) -> str:
    return email.rsplit("@", 1)[0]


def get_email_full_domain(email) -> str:
    return email.rsplit("@", 1)[1]


def get_email_domain(email) -> str:
    full_domain = get_email_full_domain(email)
    domain = full_domain.split(".")[0]
    return domain


def get_text_length(text) -> int:
    return len(text)


class NameLengthTransformer(BaseEstimator, TransformerMixin):
    def fit(self, X, y=None):
        return self

    def transform(self, X, y=None):
        return X.apply(lambda x: get_text_length(get_email_name(x))).values.reshape(
            -1, 1
        )
    
    def get_feature_names(self):
        # 修正:返回列表而非字符串
        return ["name_length"]


class DomainLengthTransformer(BaseEstimator, TransformerMixin):
    def fit(self, X, y=None):
        return self

    def transform(self, X, y=None):
        return X.apply(lambda x: get_text_length(get_email_domain(x))).values.reshape(
            -1, 1
        )
    
    def get_feature_names(self):
        # 修正:返回列表而非字符串
        return ["domain_length"]


class EmailTransformer(BaseEstimator, TransformerMixin):
    def __init__(self):
        self.email_transformer = FeatureUnion(
            [
                ("name_length", NameLengthTransformer()),
                ("domain_length", DomainLengthTransformer()),
            ]
        )

    def fit(self, X, y=None):
        # 修正:拟合内部FeatureUnion
        self.email_transformer.fit(X, y)
        return self

    def transform(self, X, y=None):
        return self.email_transformer.transform(X) 
    
    def get_feature_names(self):
        # 修正:遍历子转换器收集特征名,不使用FeatureUnion默认带前缀的逻辑
        feature_names = []
        for _, transformer in self.email_transformer.transformer_list:
            feature_names.extend(transformer.get_feature_names())
        return feature_names

# 测试代码
emails = pd.DataFrame({'email':['ladsf@gmail.com', 'pertro@gmail.com']})
et = EmailTransformer()
transform_result = et.fit_transform(X=emails['email'])
print(et.get_feature_names())

运行后输出结果为:

['name_length', 'domain_length']

完全符合预期,可以直接用这个特征名列表生成带列名的DataFrame。

内容的提问来源于stack exchange,提问作者Lucas Dresl

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 05:24:16