如何将外部功能添加到我的管道?

How do I add external features to my pipeline?

很多年前这里有人问过类似的问题,但没有答案。我也有同样的问题。在构建 Pipeline 和执行 GridSearch 找到最好的超参数。

目前,我可以使用下面的代码在没有 GridSearchPipeline 的情况下逐个模型地执行此模型。

# this is an NLP project
X = df["text"] # column of text
y = df["target"] # continuous target variable
X_train, X_unseen, y_train, y_unseen = train_test_split(X, y, test_size=0.5, stratify=df_merged["platform"], random_state=42)

# vectorize
tvec = TfidfVectorizer(stop_words="english")
X_train_tvec = tvec.fit_transform(X_train)

# get dummies
dummies = pd.get_dummies(df["dummies"]).values
# add dummies to tvec sparse matrix
X_train_tvec_dumm = hstack([X_train_tvec, dummies]).toarray()

从这里开始,我可以将我的模型拟合到 X_train_tvec_dumm 训练数据,其中包括来自 [=12= 的词向量的稀疏矩阵(形状:n_rows、n_columns) ] 和 3 个虚拟列。因此最终的形状是 (n_rows, n_columns + 3).

我尝试按如下方式构建 Pipeline

# get dummies
dummies = pd.get_dummies(df["dummies"]).values

def add_dummies(matrix):
    return hstack([matrix, dummies]).toarray()


pipe = Pipeline([
    ("features", FeatureUnion([
        ("tvec", TfidfVectorizer(stop_words="english")),
        ("dummies", add_dummies(??))    <-- how do I add this step into the pipeline?
    ])),
    ("ridge", RidgeCV())
])

pipe_params = {
    'features__tvec__max_features': [200, 500],
    'features__tvec__ngram_range': [(1,1), (1,2)]
}

gs = GridSearchCV(pipe, param_grid=pipe_params, cv=4)
gs.fit(X_train, y_train)
print(gs.best_score_)

tutorial 描述了如何为 Pipeline 构建自定义转换器,但其自定义函数添加了通过在 X_train 上进行转换而设计的新功能。不幸的是,我的虚拟变量在 X_train 集合之外。

不要使用 pandas 中的 get_dummies,而是使用 sklearn.preprocessing 中的 OneHotEncoder,以及 sklearn.compose 中的 ColumnTransformer。使用 'text' 和 'category|dummies' 列作为特征创建一个 DataFrame。

OneHotEncoder 需要整数类型的特征。如果你的特征不是int类型,先encode|map成int,然后应用OneHotEncoder.

# ...
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import OneHotEncoder


text_features = ['text']
text_transformer = Pipeline(steps=[
    ('vectorizer', TfidfVectorizer(stop_words="english"))])

categorical_features = ['category']
categorical_transformer = Pipeline(steps=[
    ('imputer', SimpleImputer(strategy='constant', fill_value='missing')),
    ('onehot', OneHotEncoder(handle_unknown='ignore'))])

preprocessor = ColumnTransformer(
    transformers=[
        ('text', text_transformer, text_features),
        ('cat', categorical_transformer, categorical_features)])


pipe =  Pipeline(steps=[('preprocessor', preprocessor),
                   ("ridge", RidgeCV())
])

# ...