对对象,sklearn管道的两列应用不同的转换

applying different transformation to two columns which are object, sklearn pipeline

我正在尝试将两种不同的转换从 sklearn 应用到两个不同的列,它们都是 object 在我的 Pipeline 中。我的 DataFrame 看起来像这样(我避免所有行只是为了说明我的观点):

             email  country  label 
fulanito@gmail.com       NI   True 
fipretko@gmail.com       AR  False
trytryyy@gmail.com       CZ   True

emailcountry都是object类型

对于 email 我创建了一堆函数来将它转换成它的一些数字表示。

喜欢:

def email_length(email) -> np.array:
    return np.array([len(e[0].split('@')[0]) for e in email]).reshape(-1, 1)

def domain_length(email) -> np.array:
    return np.array([len(e[0].split('@')[-1]) for e in email]).reshape(-1, 1)

def number_of_vouls(email) -> np.array:
    vouls = 'aeiouAEIOU'
    name = [e[0].split('@')[0] for e in email]
    return np.array([sum(1 for char in name if char in vouls) for name in name]).reshape(-1, 1)

为了将函数传递给 sklearn Pipeline 中的 email,我使用了 FunctionTransformerFeatureUnion,就像这样。

get_email_length = FunctionTransformer(email_length)
get_domain_length = FunctionTransformer(domain_length)
get_number_of_vouls = FunctionTransformer(number_of_vouls)

preproc = FeatureUnion([
        ('email_length', get_email_length),
        ('domain_length', get_domain_length),
        ('number_of_vouls', get_number_of_vouls)])

pipe = Pipeline([
        ('preproc', preproc),
        ('classifier', LGBMClassifier())
        ])

但我也想在我的 Pipeline 内部传递一个单热编码器到 country,鉴于此 Pipeline 定义,这将是最好的方法吗?

你可以试试 ColumnTransformer:

1。使用 DataFrame 输入

def email_and_domain_length(df: pd.DataFrame) -> pd.DataFrame:
    return df["email"].str.split("@", expand=True).applymap(len)


def number_of_vouls(df: pd.DataFrame) -> pd.DataFrame:
    return (
        df["email"]
        .str.split("@")
        .str[0]
        .str.lower()
        .apply(lambda x: sum(x.count(v) for v in "aeiou"))
        .to_frame()
    )


get_email_length = FunctionTransformer(email_and_domain_length)
get_number_of_vouls = FunctionTransformer(number_of_vouls)

preproc = ColumnTransformer(
    [
        ("lengths", get_email_length, ["email"]),
        ("vouls", get_number_of_vouls, ["email"]),
        ("countries", OneHotEncoder(), ["country"]),
    ]
)
preproc.fit_transform(df[["email", "country"]])

2。使用 ndarray 输入:

只需将其添加到您问题中的代码中,它已经适用于 ndarray 输入。

preproc = ColumnTransformer(
    [
        ("email_lengths", get_email_length, [0]),
        ("voul_lengths", get_domain_length, [0]),
        ("vouls", get_number_of_vouls, [0]),
        ("countries", OneHotEncoder(), [1]),
    ]
)
preproc.fit_transform(df[["email", "country"]].to_numpy())

输出:

array([[8., 9., 4., 0., 0., 1.],
       [8., 9., 3., 1., 0., 0.],
       [8., 9., 0., 0., 1., 0.]])

顺便说一句,如果 country 具有高基数,one-hot-encoding 弊大于利。

我还尝试使用 .str 访问器方法而不是列表理解来向量化预处理函数。